2016-12-13 10 views
-2

Я пытаюсь совместить мое PLINQ заявления так:Объединения PLINQ метода асинхронного

Enumerable.Range(0, _sortedList.Count()).AsParallel().WithDegreeOfParallelism(10) 
      .Select(i => GetTransactionDetails(_sortedList[i].TransactionID)) 
      .ToList(); 

С методом асинхронного, как это:

private async void GetTransactionDetails(string _trID) 
{ 
     await Task.Run(() => 
     { 
     }); 
} 

Так что я могу просто добавить оператор AWAIT здесь:

Enumerable.Range(0, _sortedList.Count()).AsParallel().WithDegreeOfParallelism(10) 
      .Select(i => await GetTransactionDetails(_sortedList[i].TransactionID)) 
      .ToList(); 

Как я могу это достичь?

P.S. Таким образом, я мог бы делать 5-10 HTTP-запросов одновременно, гарантируя, что конечный пользователь не чувствует «замораживания» экрана при этом ...

+0

Почему вы пытаетесь распараллеливать * начальную * асинхронную операцию, учитывая, что начало ее вообще будет иметь нулевое время. PLINQ для длительных операций с привязкой к процессору; это не то, что у вас есть. Кроме того, похоже, что 'GetTransactionDetails' использует асинхронный анти-шаблон. Он не должен разгружать работу в другой поток, а просто должен быть синхронным методом. Если вызывающий абонент хочет называть его «Task.Run», они могут, если они хотят сделать что-то еще, например, использовать PLINQ, тогда они могут это сделать. – Servy

+0

@Servy вы могли бы показать мне, как я могу реализовать то, что вы только что сказали, на более практическом примере? – User987

+0

Удалите 'Task.Run' из' GetTransactionDetails' и просто выполняйте эту операцию синхронно, тем самым позволяя PLINQ распараллелить его. – Servy

ответ

2

Существует пара способов, которые вы можете предпринять.

Во-первых, «более правильный» подход (который также требует больше работы). Сделать GetTransactionDetails в надлежащий async метод (т.е. не использует Task.Run):

private async Task GetTransactionDetailsAsync(string _trID); 

Тогда вы можете вызвать этот метод одновременно:

var tasks = _sortedList.Select(x => GetTransactionDetailsAsync(x.TransactionID)); 
await Task.WhenAll(tasks); 

Если вам нужно ограничить параллелизм, использовать SemaphoreSlim.

Второй подход более расточительный (с точки зрения использования потоков), но, вероятно, легче указать, какие части вашего кода мы видели. Второй подход заключается покинуть I/O все синхронные и просто сделать это в обычной PLINQ моды:

private void GetTransactionDetails(string _trID); 

_sortedList.AsParallel().WithDegreeOfParallelism(10).Select(x => GetTransactionDetails(x.TransactionID)).ToList(); 

Чтобы избежать блокирования потока пользовательского интерфейса, вы можете обернуть это в одном Task.Run:

await Task.Run(() => _sortedList.AsParallel().WithDegreeOfParallelism(10).Select(x => GetTransactionDetails(x.TransactionID)).ToList()); 
+0

Ясно Удивительный ответ, спасибо! Ожидание Task.Run() Именно то, что мне нужно в этом случае ... Хотя мне пришлось использовать Parallel.For с комбинацией цикла Parallel.For вместо того, который вы показали в примере, потому что. Метод выбора doesn ' t работать с void методами, по крайней мере, то, что показал мне компилятор? – User987

+0

У меня есть методы async с привязкой к процессору, которые выполняют крошечный бит ввода-вывода, но их нужно распараллелить для связанных с процессором материалов. Используемые интерфейсы не имеют синхронного API. То, что я сделал, это «Task.WhenAll (items.Select (item => Task.Run (async() => {/ * метод, который ждет * /})))'. Task.Run предназначен для обработки связанной с CPU работы, которая происходит до первого ожидания. Кажется, что очередь на все пулы в пул потоков пока остается самой быстрой. – jnm2

+0

В любом случае, я не думаю, что когда-либо тратит нить на IO. – jnm2