Мое предположение: большинство трудоемких операций будут получать данные с помощью операции GET и фактический вызов WriteToServer
с использованием SqlBulkCopy
.Если вы посмотрите на этот класс, то увидите, что существует нативный асинхронный метод WriteToServerAsync
method ( здесь ).Всегда используйте их перед созданием Задач самостоятельно, используя Task.Run
.
То же самое относится и к вызову http GET.Для этого вы можете использовать собственные HttpClient.GetAsync
( документы здесь ).
Таким образом вы можете переписать свой код следующим образом:
private async Task ProcessFileAsync(string series_id)
{
string json = await GetAsync();
SeriesObject obj = JsonConvert.DeserializeObject<SeriesObject>(json);
DataTable dataTableConversion = ConvertToDataTable(obj.observations);
dataTableConversion.TableName = series_id;
using (SqlConnection dbConnection = new SqlConnection("SQL Connection"))
{
dbConnection.Open();
using (SqlBulkCopy s = new SqlBulkCopy(dbConnection))
{
s.DestinationTableName = dataTableConversion.TableName;
foreach (var column in dataTableConversion.Columns)
s.ColumnMappings.Add(column.ToString(), column.ToString());
await s.WriteToServerAsync(dataTableConversion);
}
Console.WriteLine("File: {0} Complete", series_id);
}
}
private async Task SQLBulkLoaderAsync()
{
var tasks = indicators.file_list.Select(f => ProcessFileAsync(f.series_id));
await Task.WhenAll(tasks);
}
Обе операции (httpвызов и вызов сервера sql) являются вызовами ввода / вывода.При использовании нативного шаблона async / await даже не будет создан или использован поток, см. этот вопрос для более подробного объяснения.Вот почему для операций, связанных с вводом-выводом, вам никогда не придется использовать Task.Run
(или Task.Factory.StartNew
. Но учтите, что Task.Run
является рекомендуемым подходом ).
Sidenote: ifвы используете HttpClient
в цикле, прочитайте это о том, как правильно его использовать.
Если вам нужно ограничить количество параллельных действий, вы также можете использовать TPLПоток данных , поскольку он очень хорошо работает с операциями, связанными с вводом-выводом на основе задач.Затем SQLBulkLoaderAsync
следует изменить на (оставив метод ProcessFileAsync
из предыдущего ответа без изменений):
private async Task SQLBulkLoaderAsync()
{
var ab = new ActionBlock<string>(ProcessFileAsync, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5 });
foreach (var file in indicators.file_list)
{
ab.Post(file.series_id);
}
ab.Complete();
await ab.Completion;
}