多线程/异步请求,等待所有请求完成后再处理结果

5
我需要执行一个针对多个来源的搜索请求。 我之前进行过一些多线程编程,但都是“发射即忘”。 现在我想要做的是,在三个不同的对象上启动3个相同的请求,等待它们全部完成(这就带来了第一个问题:它们如何表达“我完成了”),然后收集它们发送给我的所有数据。
因此,在伪代码中,我有以下接口:
interface ISearch
    SearchResult SearchForContent(SearchCriteria criteria)

因此,在代码中我创建了三个搜索服务:

ISearch s1 = new SearchLocal();
ISearch s2 = new SearchThere();
ISearch s3 = new SearchHere();

然后以多线程/异步方式在这三个对象上调用SearchForContent(SearchCriteria criteria),然后它们都会带着它们的SearchResult回到我这里,等它们都完成后,我会处理它们的SearchResult对象。
希望这些文字让您更好地理解我的想法 :)
我正在开发一个ASP.Net 3.5 C#项目。

2
使用“Task”对象是最简单的方法。它们在.NET 4中引入,但已经在(不受支持,自行承担风险)Rx库中进行了回溯。您是否可以使用Rx,或者需要一个纯.NET 3.5的解决方案? - Stephen Cleary
不好意思,我需要一个纯粹的3.5解决方案。 - Michel
唉,我现在才看到关于3.5的注释,我猜任务对你来说就行不通了。 - BrokenGlass
3个回答

6

创建AutoResetEvent并将其传递给WaitHandle.WaitAll()

这里有一个示例here

基本上:

1)为每个搜索创建一个AutoResetEvent,并在其构造函数中传递false

2)创建线程并运行每个线程的搜索,在最后,在finally块中调用AutoResetEvent上的Set非常重要的是,在finally块内调用Set,否则WaitAll()将无限期等待。

3)在生成线程后的代码中,调用WaitHandle.WaitAll()并将所有那些AutoResetEvent传递给它。此代码将等待直到所有都完成。


@Aliostad,您需要修改ISearch实现,以便在其构造函数中接受AutoResetEvents(或您选择的任何等待句柄)。此外,您需要添加一种异步访问结果的方法(例如,ISearch.SearchResults { get; })。 - Jeff Sternal
@Jeff 是的,通过更改ISearch以接受AutoResetEvent是正确的。但我不同意第二部分,在WaitAll()返回后,搜索结果将由主线程使用。 - Aliostad
@Aliostad,所以我将创建的AutoResetEvent对象传递给搜索类,然后在搜索类中调用该AutoResetEvent对象上的Set。如果我在搜索类中创建一个属性来包含搜索结果,在WaitHandle.WaitAll()完成等待后就可以访问它了吗? - Michel
我在想,在这个解决方案中,我等待所有三个任务都结束。是否也有可能在第一个任务准备好时得到通知呢?因此,如果其中一个任务花费1秒钟执行搜索请求,而另外两个任务需要50秒钟,那么我是否可以在等待另外两个任务的同时,在第一次加载搜索结果时进行一些逻辑处理呢? - Michel
1
不行。这需要将继续任务构建到异步操作本身中。 - Aliostad
显示剩余7条评论

2
使用任务,您可以进行如下的连续操作:
        Task[] t = new Task[2];
        t[0] = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
        t[1] = Task.Factory.StartNew(() => { Thread.Sleep(2000); });

        Task.Factory.ContinueWhenAll(t, myTasks => { Console.WriteLine("All done!"); });

确实是3.5版本,但还是感谢你提供代码,毕竟不知道什么时候会在4.0项目中用到它! - Michel

0
创建一个 IEnumerable<ISearch>,将项目添加到其中,并在其上执行 .AsParallel().ForAll(...)。 < p > 编辑

如果可以更改 ISearch,请为其添加结果属性,然后一旦 ForAll 完成,您可以通过 IEnumerable 查看结果。

是的,抱歉,这是 4.0 版本。


1
ForAll 不会返回结果。 - Scott Chamberlain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接