1

(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,不会阻塞主线程(在我的例子中是一个 UI 线程)。问题是:它为ts. 有没有一种(简单的)方法可以只使用一个线程来完成整个工作?

所以,为了让自己清楚,我想只使用一个线程生成这些项目,但我需要获取某种Tasks (或任何其他带有 a 的类GetAwaiter)的集合,以便await在生成这些项目中的每一个之后.

4

2 回答 2

1

您现有的解决方案不会为每个项目生成一个线程。相反,它创建一个线程池工作项,该工作项排队到线程池,每个项一次。有可能(甚至很可能)每个MoveNext线程实际上都由同一个线程池线程完成。

因此,鉴于您的限制,我认为您现有的解决方案将起作用。

如果您可以完全更改可枚举,我会考虑IAsyncEnumerator<T>,它有一个Task<bool> MoveNext()成员。IAsyncEnumerator<T>/IAsyncEnumerable<T>Ix_Experimental-Async的一部分。我还写了一个几乎相同的IAsyncEnumerator<T>,它是Nito.AsyncEx的一部分。异步枚举与您尝试做的事情更接近;有一个Channel9 视频描述了异步枚举(尽管 API 从那时起略有变化)。

于 2012-01-07T20:53:49.507 回答
0

如果您只想在另一个线程上通过 ts 运行,您可以执行以下操作:

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

它只是在线程池中的一个线程上运行。

更新:所以操作确实 ui 工作,这意味着它需要在 ui 线程上排队。你没有说你使用哪个 ui 框架,但他们都有办法做到这一点。

例如,如果您使用 wpf,则可以使用调度程序

于 2012-01-07T20:38:52.823 回答