C# 在Foreach中等待异步事件完成

C# 在Foreach中等待异步事件完成,c#,C#,我如何使用foreach向服务器发送请求,当我得到响应时,foreach将等待返回的信息进行处理,然后再继续下一个请求 我的问题是:在foreach中,我发送了许多请求,而foreach没有处理我得到的响应信息 例如: foreach (DataLoader.GetInfo items in listBoxFetInfo.Items) { DownloadInfo(items.CompanyName); } 及 及 及 我无法使用,因为此解

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

我的问题是:在foreach中,我发送了许多请求,而foreach没有处理我得到的响应信息

例如:

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

我无法使用,因为此解决方案需要添加CancellationToken,其中我无法添加(不能在void feed\u RequestName中添加)

这个问题还有什么解决办法

此外,我不能更改以下人员的签名:

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


你能用while代替foreach吗

比如:


关于你的东西是如何工作的,我在这里暗中试探,但这是我要做的。因为你不能修改签名,你不能像你建议的那样使用
任务

我在这里看到的是,您有一个方法开始一个请求,然后在请求完成时调用一个事件。我假设您的请求运行在一个单独的线程上,或者运行在
feed
所在的库中。您需要做的是等待该事件完成一次,然后再继续下一项。如果这不是你要问的问题或者你的库是如何工作的,请告诉我

如果您不是并行执行请求(意味着一次只执行一个请求,没有其他人使用您的
提要
对象),则可以使用
System.Threading.ManualResetEvent
类使一个方法非常容易地依赖于另一个方法。您可以执行以下操作:

  • 在您的
    DownloadInfo
    方法中,
    Reset
    重置
    ManualResetEvent
    ,这样每当有人调用
    WaitOne
    ,它都会“阻止”线程并阻止它继续运行。它会等到有人调用
    ManualResetEvent
    上的
    Set

  • 调用获取
    请求ID的方法后,在
    ManualResetEvent
    上调用
    WaitOne
    。这将等待“其他人”在
    ManualResetEvent
    上调用
    Set

  • 在您的
    feed\u RequestName
    方法中,
    Set
    一旦完成处理,就会设置手动重置事件。这将使您在步骤2中调用的
    WaitOne
    停止阻塞并继续。如果您在调用
    Set
    之前将请求的结果存储在这些东西所在的对象上的一些变量中,y您可以在
    WaitOne
    之后通过
    DownloadInfo
    方法访问结果

  • 一个简短而不完整的例子:

    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();
        }
    }
    
    重要提示:如果您的
    提要
    在多个可以同时执行的对象之间共享,您需要确保不会将其他对象的请求与您的
    DownloadInfo
    方法发出的请求进行交互。任何请求都会导致调用您的
    提要\u RequestName
    方法o您需要找出该方法的哪个调用与您的请求相对应。以下是一条如何使该方法起作用的建议:

  • 将您在
    DownloadInfo
    中获得的
    requestId
    存储在
    feed\u RequestName
    可以访问的地方。如果在调用方法有机会执行之前调用了
    feed\u RequestName
    ,则可能会出现问题。您需要找出解决此问题的方法
  • feed_RequestName
    中,与存储的请求id进行比较,如果匹配,仅调用
    ManualResetEvent
    上的
    Set
  • 另一个注意事项:您的库面向并行执行请求。在执行下一个请求之前等待请求完成的效率非常低。您真正应该做的是(psuedocode):


    我想我们可能需要更多的信息。什么是
    DataLoader
    列表中项目的信息当我单击“开始”时,我的程序没有响应,可能是因为在主类中我创建了void:public void SetMre(){u mre.Set();}在另一个类中的feed_RequestName中使用它。这是真的吗?您如何编写和使用它,thanx很多,但有一些功能:当我启动程序时,我的程序没有响应。我可以在另一个线程中启动这个吗?例如在foreach中,我有:this.Dispatcher.BeginInvoke(新线程启动(委托{ProgressDataLoad.Value++}));这不起作用主要的问题是:我发送了大约1000个请求,但可以发送大约250个,现在这个问题-因为工作没有问题)提供<代码>提要的库是什么?我在这个答案中展示的方法只有在库启动另一个线程来执行请求时才有效。据猜测,该库正在线程池上启动线程或执行作业。您需要使用调试器并逐步查看是否正在调用
    feed\u RequestName
    方法,并确定何时调用该方法。
    void feed_RequestName(int originalRequestId, short ResponseCode, string symbol, short symbolStatusCode, object records)
    {
    //save to file
    }
    
    feed_RequestName(int originalRequestId, short ResponseCode, string symbol, short symbolStatusCode, object records)
    
    feed.SendCompanyNameRequest(symbol.ToUpper(), sendType, sendTimePeriod, sendDateFrom, DateTime.Now);
    
    while(not done processing all requests) {
      //grab and process next request
    }
    
    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();
        }
    }
    
    DownloadItems:
        Lock the object so that only one person uses the method at a time
        foreach item in requests
            call your start request method and get the id
            put the id into a thread-safe set stored on the object
        wait for the set to become empty
    
    feed_RequestName:
        Do your thing that you've been doing
        Remove the id from the thread safe set