Ожидание создания нескольких элементов в одном потоке - PullRequest
1 голос
/ 08 января 2012

(OBS: английский не является моим родным языком, и я понимаю, что название этого вопроса далеко от хорошего, но я изо всех сил старался прояснить сам вопрос)

Предположим, у меня есть IEnumerable<T> ts, который имеет МНОГО элементов и каждый MoveNext () ОЧЕНЬ дорогой - скажем, ts был сгенерирован с использованием метода yield return, который делает дорогие вычисления.

Посмотрите на эту частькода:

var enumerator = ts.GetEnumerator();
while (true) {
    T t = await TaskEx.Run<T>(() => enumerator.MoveNext() ? 
                                    enumerator.Current : 
                                    null);
    if (t == null) break;
    t.DoSomeLightweigthOperation(); 
}

Он использует коллекцию ts асинхронно, без блокировки основного потока (который, в моем случае, является потоком пользовательского интерфейса).Проблема в том, что он порождает одну нить для каждого элемента в ts.Есть ли (простой) способ сделать то же самое, используя только ОДИН поток, который выполняет всю работу?

Итак, чтобы прояснить ситуацию, я хочу сгенерировать эти элементы, используя только один поток, но мне нужночтобы получить какой-то набор Task с (или любой другой класс с GetAwaiter), чтобы я мог await после генерации каждого из этих элементов.

Ответы [ 2 ]

1 голос
/ 08 января 2012

Ваше существующее решение не порождает одну нить для каждого элемента. Скорее, он создает рабочий элемент пула потоков, который ставится в очередь в пуле потоков, по одному разу для каждого элемента. Возможно (даже вероятно), что каждый MoveNext будет фактически выполняться одним и тем же потоком потоков.

Итак, я думаю, что ваше существующее решение будет работать, учитывая ваши ограничения.

Если вы вообще можете изменить перечисляемое значение, я бы рассмотрел IAsyncEnumerator<T>, в котором есть Task<bool> MoveNext() член. IAsyncEnumerator<T> / IAsyncEnumerable<T> являются частью Ix_Experimental-Async . Я также написал почти идентичный IAsyncEnumerator<T>, который является частью Nito.AsyncEx . Асинхронное перечисление ближе к тому, что вы пытаетесь сделать; есть Channel9 видео , которое описывает асинхронное перечисление (хотя API немного изменилось с тех пор).

0 голосов
/ 08 января 2012

Если все, что вы хотите сделать, это запустить ts в другом потоке, вы можете сделать что-то вроде этого:

ThreadPool.QueueUserWorkItem(_ => 
{
   foreach(T t in ts)
   {
       t.DoSomeLightweigthOperation();
   }
});

Который просто проходит через нить из пула потоков.

ОБНОВЛЕНИЕ: Таким образом, операция работает с пользовательским интерфейсом, что означает, что она должна быть поставлена ​​в очередь в пользовательском интерфейсе. Вы не говорите, какой пользовательский интерфейс вы используете, но у всех есть способы сделать это.

Например, если вы используете wpf, вы можете использовать диспетчер

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...