等待Foreach中的异步事件完成

时间:2015-04-20 17:17:49

标签: c#

如何使用foreach向服务器发送请求,当我收到响应时,foreach等待返回的信息进行处理,然后再继续下一个请求。

我的问题:在foreach中,我发送了许多请求,并且foreach继续进行,没有我获得回应的信息。

例如:

foreach (DataLoader.GetInfo items in listBoxFetInfo.Items)
{  
    DownloadInfo(items.CompanyName);                     
}

void DownloadInfo(string name)
{
   int requestId = feed.SendCompanyNameRequest(symbol.ToUpper(), sendType, sendTimePeriod, sendDateFrom, DateTime.Now);
}

feed.RequestCompanyName += new IFeedEvents_RequestCompanyNameEventHandler(feed_RequestName);

void feed_RequestName(int originalRequestId, short ResponseCode, string symbol, short symbolStatusCode, object records)
{
//save to file
}

我无法使用Start Multiple Async Tasks and Process Them As They Complete ,因为此解决方案需要添加CancellationToken,我无法添加(不能无效feed_RequestName

这个问题可以解决另一个问题吗?

另外,我无法更改签名:

feed_RequestName(int originalRequestId, short ResponseCode, string symbol, short symbolStatusCode, object records)

feed.SendCompanyNameRequest(symbol.ToUpper(), sendType, sendTimePeriod, sendDateFrom, DateTime.Now);

2 个答案:

答案 0 :(得分:0)

你可以使用while而不是foreach吗?

像:

while(not done processing all requests) {
  //grab and process next request
}

答案 1 :(得分:0)

我在黑暗中捅了一下你的事情如何运作,但这就是我要做的。由于您无法修改签名,因此您无法使用Task,就像您提出的last question一样。

我在这里看到的是,您有一个方法可以开始请求,然后是一个在请求完成时调用的事件。我假设您的请求是在单独的线程上运行的,或者是feed所在的库内的某个东西。您需要做的是等待该事件完成一次,然后再继续下一个项目。如果您的问题不在于您的问题或图书馆的运作方式,请与我们联系。

如果您并行执行请求(意味着一次只执行一个请求而其他人没有使用您的feed对象),您可以使用{{1} } class让你的一个方法非常容易依赖于另一个方法。你能做的是以下几点:

  1. System.Threading.ManualResetEvent方法中,DownloadInfo Reset,以便每当有人拨打ManualResetEvent时,它都会"阻止"线程并阻止它继续下去。它会等到其他人在WaitOne上调用Set

  2. 在调用获取ManualResetEvent的方法后,请致电requestId上的WaitOne。这将等到"其他人"在ManualResetEvent上调用Set

  3. 完成处理后,在ManualResetEvent方法中,feed_RequestName手动重置事件。这将使您在步骤2中调用的Set停止阻止并继续。如果您在调用WaitOne之前将请求的结果存储在这些内容所包含的对象的某些变量中,则可以在Set后的DownloadInfo方法中访问结果。

  4. 一个简短的,不完整的例子:

    WaitOne

    重要提示:如果您的class YourClassWhereYouPutTheseThings { private ManualResetEvent _mre = new ManualResetEvent(true); //...your other stuff here... public YourClassWhereYouPutTheseThings() { //...your existing stuff feed.RequestCompanyName += new IFeedEvents_RequestCompanyNameEventHandler(feed_RequestName); //...your existing stuff } void YourMethod() { foreach (DataLoader.GetInfo items in listBoxFetInfo.Items) { DownloadInfo(items.CompanyName); } } void DownloadInfo(string name) { this._mre.Reset(); //make everyone listening to _mre wait until Set is called int requestId = feed.SendCompanyNameRequest(symbol.ToUpper(), sendType, sendTimePeriod, sendDateFrom, DateTime.Now); this._mre.WaitOne(); //wait for the feed_RequestName method to be called once } void feed_RequestName(int originalRequestId, short ResponseCode, string symbol, short symbolStatusCode, object records) { //save to file //store your information on the object somewhere if you would like //after saving to your file, set the manualresetevent so that the WaitOne() above can proceed this._mre.Set(); } } 在可以同时执行的多个对象之间共享,则需要确保不要通过其他对象进行插入请求作为您feed方法的请求。任何请求都会导致调用DownloadInfo方法,因此您需要确定该方法的哪个调用与您的请求相对应。以下是关于如何开展工作的一个建议:

    1. feed_RequestName存储在requestId DownloadInfo可以访问的地方。如果在调用方法有机会执行之前调用feed_RequestName,则可能会出现问题。你需要找到解决这个问题的方法。
    2. feed_RequestName中,与已存储的请求ID进行比较,只有在feed_RequestName匹配时才会调用Set
    3. 另一个注释:您的图书馆适合并行执行请求。在进入下一个请求之前等待请求完成是非常低效的。你真正应该做的是像(伪代码):

      ManualResetEvent