이 질문은 후속 조치로 Using HttpClient for Asynchronous File downloads입니다.비동기 파일 다운로드에 HttpClient를 사용할 때 스레딩 문제가 발생합니다.
2015년 1월 15일 편집은 멀티 스레딩을위한 숙박에 추가 - 여전히 신비가,
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace TestHttpClient2
{
class Program
{
/* Use Yahoo portal to access quotes for stocks - perform asynchronous operations. */
static string baseUrl = "http://real-chart.finance.yahoo.com/";
static string requestUrlFormat = "/table.csv?s={0}&d=0&e=1&f=2016&g=d&a=0&b=1&c=1901&ignore=.csv";
static void Main(string[] args)
{
var activeTaskList = new List<Task>();
string outputDirectory = "StockQuotes";
if (!Directory.Exists(outputDirectory))
{
Directory.CreateDirectory(outputDirectory);
}
while (true)
{
Console.WriteLine("Enter symbol or [ENTER] to exit:");
string symbol = Console.ReadLine();
if (string.IsNullOrEmpty(symbol))
{
break;
}
Task downloadTask = DownloadDataForStockAsync(outputDirectory, symbol);
if (TaskIsActive(downloadTask))
{
// This is an asynchronous world - lock the list before updating it!
lock (activeTaskList)
{
activeTaskList.Add(downloadTask);
}
}
else
{
Console.WriteLine("task completed already?!??!?");
}
CleanupTasks(activeTaskList);
}
Console.WriteLine("Cleaning up");
while (CleanupTasks(activeTaskList))
{
Task.Delay(1).Wait();
}
}
private static bool CleanupTasks(List<Task> activeTaskList)
{
// reverse loop to allow list item deletions
// This is an asynchronous world - lock the list before updating it!
lock (activeTaskList)
{
for (int i = activeTaskList.Count - 1; i >= 0; i--)
{
if (!TaskIsActive(activeTaskList[i]))
{
activeTaskList.RemoveAt(i);
}
}
return activeTaskList.Count > 0;
}
}
private static bool TaskIsActive(Task task)
{
return task != null
&& task.Status != TaskStatus.Canceled
&& task.Status != TaskStatus.Faulted
&& task.Status != TaskStatus.RanToCompletion;
}
static async Task DownloadDataForStockAsync(string outputDirectory, string symbol)
{
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUrl);
client.Timeout = TimeSpan.FromMinutes(5);
string requestUrl = string.Format(requestUrlFormat, symbol);
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var sendTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var response = await sendTask;
response.EnsureSuccessStatusCode();
var httpStream = await response.Content.ReadAsStreamAsync();
string timestampedName = FormatTimestampedString(symbol, true);
var filePath = Path.Combine(outputDirectory, timestampedName + ".csv");
using (var fileStream = File.Create(filePath))
using (var reader = new StreamReader(httpStream))
{
await httpStream.CopyToAsync(fileStream);
fileStream.Flush();
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception on thread: {0}: {1}\r\n",
System.Threading.Thread.CurrentThread.ManagedThreadId,
ex.Message,
ex.StackTrace);
}
}
static volatile string lastTimestampedString = string.Empty;
static volatile string dummy = string.Empty;
static HashSet<string> oldStrings = new HashSet<string>();
static string FormatTimestampedString(string message, bool uniquify = false)
{
// This is an asynchronous world - lock the shared resource before using it!
//lock (dummy)
lock (lastTimestampedString)
{
Console.WriteLine("IN - Thread: {0:D2} lastTimestampedString: {1}",
System.Threading.Thread.CurrentThread.ManagedThreadId,
lastTimestampedString);
string newTimestampedString;
while (true)
{
DateTime lastDateTime = DateTime.Now;
newTimestampedString = string.Format(
"{1:D4}_{2:D2}_{3:D2}_{4:D2}_{5:D2}_{6:D2}_{7:D3}_{0}",
message,
lastDateTime.Year, lastDateTime.Month, lastDateTime.Day,
lastDateTime.Hour, lastDateTime.Minute, lastDateTime.Second,
lastDateTime.Millisecond
);
if (!uniquify)
{
break;
}
if (newTimestampedString != lastTimestampedString)
{
break;
}
//Task.Delay(1).Wait();
};
lastTimestampedString = newTimestampedString;
Console.WriteLine("OUT - Thread: {0:D2} lastTimestampedString: {1}",
System.Threading.Thread.CurrentThread.ManagedThreadId,
lastTimestampedString);
if (uniquify)
{
oldStrings.Add(lastTimestampedString);
}
return lastTimestampedString;
}
}
}
}
Q)를하는 이유는이 출력의 끝이 간헐적으로 오류를 (얻고) (나는. 위해 콘솔에 클립 보드 및 붙여 넣기를 "NES"의 반복 라인의 긴 목록을 복사하는) 문제를 복제 :
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
NES
Enter symbol or [ENTER] to exit:
IN - Thread: 18 lastTimestampedString:
OUT - Thread: 18 lastTimestampedString: 2015_01_15_11_19_44_472_NES
IN - Thread: 17 lastTimestampedString: 2015_01_15_11_19_44_472_NES
OUT - Thread: 17 lastTimestampedString: 2015_01_15_11_19_44_473_NES
IN - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_473_NES
OUT - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_493_NES
IN - Thread: 16 lastTimestampedString: 2015_01_15_11_19_44_493_NES
OUT - Thread: 16 lastTimestampedString: 2015_01_15_11_19_44_494_NES
IN - Thread: 18 lastTimestampedString: 2015_01_15_11_19_44_494_NES
OUT - Thread: 18 lastTimestampedString: 2015_01_15_11_19_44_495_NES
IN - Thread: 17 lastTimestampedString: 2015_01_15_11_19_44_495_NES
IN - Thread: 16 lastTimestampedString: 2015_01_15_11_19_44_495_NES
OUT - Thread: 17 lastTimestampedString: 2015_01_15_11_19_44_496_NES
IN - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_495_NES
OUT - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_496_NES
IN - Thread: 18 lastTimestampedString: 2015_01_15_11_19_44_496_NES
OUT - Thread: 16 lastTimestampedString: 2015_01_15_11_19_44_495_NES
OUT - Thread: 18 lastTimestampedString: 2015_01_15_11_19_44_497_NES
IN - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_497_NES
OUT - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_523_NES
IN - Thread: 18 lastTimestampedString: 2015_01_15_11_19_44_523_NES
OUT - Thread: 18 lastTimestampedString: 2015_01_15_11_19_44_532_NES
IN - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_532_NES
OUT - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_533_NES
IN - Thread: 18 lastTimestampedString: 2015_01_15_11_19_44_533_NES
Exception on thread: 17: The process cannot access the file 'C:\Users\drogers\_code\Tests\TestHttpClient\TestHttpClient2\bin\Debug\StockQuot
es\2015_01_15_11_19_44_495_NES.csv' because it is being used by another process.
Exception on thread: 16: The process cannot access the file 'C:\Users\drogers\_code\Tests\TestHttpClient\TestHttpClient2\bin\Debug\StockQuot
es\2015_01_15_11_19_44_496_NES.csv' because it is being used by another process.
OUT - Thread: 18 lastTimestampedString: 2015_01_15_11_19_44_540_NES
IN - Thread: 17 lastTimestampedString: 2015_01_15_11_19_44_540_NES
IN - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_540_NES
OUT - Thread: 17 lastTimestampedString: 2015_01_15_11_19_44_557_NES
OUT - Thread: 19 lastTimestampedString: 2015_01_15_11_19_44_560_NES
Exception on thread: 19: The process cannot access the file 'C:\Users\drogers\_code\Tests\TestHttpClient\TestHttpClient2\bin\Debug\StockQuot
es\2015_01_15_11_19_44_560_NES.csv' because it is being used by another process.
내가 라인 (126)의 주석을 해제와 문제 및 라인 (127) 주석을 피할 수 있습니다, 예 :
01 당신은 같은 파일에 주식 데이터를 작성하려고이 작업을ldsfld string modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile)
TestHttpClient2.Program::**lastTimestampedString**
ldsfld string modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile)
TestHttpClient2.Program::**dummy**
예외가 발생해도 파일을 쓰지 마십시오. 동일한 정확한 타임 스탬프를 사용하여 밀리 초 단위로 데이터를 작성하는 것은 실제로는 유용하지 않을 것입니다. 동일한 이름을 가진 파일이 이미 있으면 파일을 다시 쓰는 것을 건너 뛸 수 있습니다. 경고 : 당신은 이것을 테스트하기 위해'File.Exists()'를 호출 할 수 없다; 실제로 파일을 만들려고 시도하고 예외가 발생하면 catch해야합니다. 'FileStream'을'FileMode.CreateNew'와 함께 직접 사용하는 것을 고려해보고 가능한 예외와 이미 존재하는 파일을 더 쉽게 구분할 수 있도록하십시오. –
요점은 선택한 명명 알고리즘을 기반으로 중복 된 리소스 이름을 만드는 것을 피하는 것입니다. –