我正在使用位于(例如)StreamReader
或SqlDataReader
之上的界面。该接口公开了一个方法GetNext()
,如果有任何一个,则返回一个对象;如果没有,则返回null
。
public interface ICollectionWidget<T>
{
T GetNext(); // Returns a T if there are any left, or null if there aren't
}
我需要并行处理T
返回的每个GetNext()
,并在GetNext()
返回null
时停止处理。我不太确定这是怎么做的(使用TPL或其他)。我需要一种并行的while
!显然,当我得到null
时,我不希望任何线程仍在处理完成,我只是不想添加任何新处理 - 然后在所有线程完成时退出'循环'他们正在做什么。
有人可以帮忙吗?如果我的问题没有意义,请告诉我。
答案 0 :(得分:5)
请注意,您展示的“集合”通常会通过IEnumerable<T>
公开。如果您可以控制API本身,我会使用IEnumerable<T>
而不是基于GetNext()
的迭代方法。但是,如果不这样做,则执行转换很简单...
我会将此API包装为IEnumerable<T>
。然后,您可以使用Parallel.ForEach
:
private IEnumerable<T> EnumerateWidgets<T>(ICollectionWidget<T> widgets)
{
T element = widgets.GetNext();
while (element != null)
{
yield return element;
element = widgets.GetNext();
}
}
然后你可以使用:
Parallel.ForEach(EnumerateWidgets(widgetCollection), widget =>
{
// Process widget here
});
这将在枚举小部件时防止线程问题(因为枚举器将是单线程的),但允许您并行处理集合。
答案 1 :(得分:1)
只需创建一个迭代器:
public interface ICollectionWidget<T>
{
IEnumerable<T> GetItems();
}
public class CollectionWidget : ICollectionWidget<int>
{
public IEnumerable<int> GetItems()
{
var i = 0;
while (i++ < 10)
{
yield return i;
}
yield break;
}
}
并在Parallel
中使用它:
var widget = new CollectionWidget();
Parallel.ForEach(widget.GetItems(), i => Console.WriteLine(i));
答案 2 :(得分:-1)
您也可以使用
Task.Factory.StartNew()