2

我需要一些有关 ConcurrentQueue 和 BlockingCollection 的帮助。

该场景是我试图限制请求并符合每秒 1 个请求的限制,当我从队列中取出一个项目时会发生限制。该应用程序是一个 MVC 4 应用程序,因此在任何给定时间都可能有多个生产者,并且我只联系一个消费者/Web 服务。

  • ProducerGetUser(string url)会向队列中添加一个 Request,一个 request 只是一个 url。
  • 通过执行一些检查来处理 BlockingCollection 中的第一项,以确保它不违反限制。
  • 下载消费者的回复
  • 然后以某种方式将下载响应返回给调用方法。节流下载

简而言之,我想处理队列中的一个项目,下载响应并将其发送回调用方法。将其发送回调用方法是我卡住的地方。我在这里有什么选择?

//I want to do something like this, and wait for the throttled response to return
public class WebService()
{
    public string GetUser(string name) 
    {
         var url = buildUrl(name);

         var response = string.Empty;

         var downloadTask = Task.Factory.StartNew( () => {
               response = WebServiceHelper.ThrottledDownload(url);
         });
         downloadTask.Wait();
         return response;
    }
}

public static class WebServiceHelper()
{
  private static BlockingCollection<Request> requests = new BlockingCollection<Request>();

  static WebServiceHelper()
  {
       foreach(var item in requests.GetEnumerableConsumer()) {
         string response = DoWork(item.Url);
         //How can i send this back to the calling method?
       }
  }

  public static string ThrottledDownload(string url)
  {
     //Add the request to the blocking queue 
     requests.Add(new Request(url, someId));

     //How do i get the result of the DoWork method?
  } 
}
4

1 回答 1

1

您可能不想向该ThrottledDown方法“返回结果”。至少,我不会这么认为。如果您确实想这样做,则必须进行某种阻塞呼叫。或者使用Task带有延续的...也许async在 C# 5 中。

目前还不清楚主线程在做什么。我假设它正在排队消费者线程每隔一秒处理的一堆请求(大概是为了防止你被你正在查询的服务器限制)。然后,您希望通知主线程(或某事),以便它可以...做某事。

您的程序流程仍不清楚。

根据您希望主线程执行的操作(以及您希望它使用的信息),您有多种选择。你可以:

  • 创建另一个BlockingCollection结果。当消费者完成一个请求时,它会将一个对象添加到该集合中。主线程轮询该集合以获取请求完成的通知。
  • 上面的一个变体是使用管道。一个线程将请求排队。一个线程将请求出列,发出 Web 请求,然后将结果放入另一个队列。第三个线程处理第二个队列。
  • 为每个对象添加一个事件(ManualResetEventSlim例如 ) 。Request消费者Set在完成请求后调用该事件。主线程要么等待该事件,要么定期轮询它。
  • 让消费者执行一个回调函数(在编译时定义,或传入Request您添加到队列中的对象)。该回调函数可以通知主线程、记录结果或您喜欢的任何内容。

同样,如果没有有关您的应用程序的更多信息以及您要解决的更高级别的问题,很难提出更具体的建议。

于 2013-03-26T20:30:46.600 回答