适当的并发方法来获取URL的状态编号

时间:2019-03-12 04:32:24

标签: c#

我试图了解可用的并发方法,并试图了解哪种方法更适合我的当前情况。我的工作是获取URL列表的状态,无论它们同时返回HTTPStatus OK还是Not OK,限制线程数,并确保所提供的最大线程始终运行所有时间,而与批处理线程无关执行。为此,我尝试使用Task Parallel Library,并且工作正常。

代码

 var parallelOptions = new ParallelOptions
 {
     MaxDegreeOfParallelism = 3
 };
 Parallel.ForEach(ListMonitorUrl, parallelOptions, i =>
 {
     LogMailError("URL: " + i.URL + " DateTime: " + DateTime.Now + " Thread ID: " + Thread.CurrentThread.ManagedThreadId, LogFile);
     VerifyWebAppUrl(i);
 });

  public MonitorURLs VerifyWebAppUrl(MonitorURLs Model)
  {
      List<string> UrlsWithNotOKResponse = new List<string>();

      try
      {
          var request = (HttpWebRequest)WebRequest.Create(Model.URL);
          using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
          {
              if (response.StatusCode != HttpStatusCode.OK && Model.Status == "A")
                  Model.ChangeOfStatus = true;
              if (response.StatusCode == HttpStatusCode.OK && Model.Status != "A")
                  Model.ChangeOfStatus = true;
          }
      }
      catch (Exception ex)
      {
          Model.ChangeOfStatus = false;
      }
      return Model;
  }

我已经看到还有其他方法,例如SemaphoreSlimTask。但是我不确定哪个最适合我的情况。请提出建议。

1 个答案:

答案 0 :(得分:2)

Parallel.ForEach完全不适合 IO绑定工作负载,您正在用尽宝贵的资源等待 IO完成端口,并限制了默认任务计划程序 / 线程池(这不仅会不必要地造成瓶颈,还会使应用程序的其他部分饿死)。

正确的方法将是支持异步等待模式的东西,例如Task.WhenAll响应式扩展 TPL DataFlow

这是一个简单的Microsoft TPL DataFlow 示例。您可以在这里System.Threading.Tasks.Dataflow

优点是

  1. 它与 Async Await Pattern
  2. 开箱即用
  3. 您可以控制最大并行度,选择尽可能多的系统/应用程序可以处理(这可以设置得比Parallel.ForEach大得多)
  4. 易于使用。
  5. 准备就绪后,您可以创建更复杂的处理管道
  6. 您将不会限制线程池,并且会更加高效和高效

示例

public async List<Model> GetDeadUrls(List<Model> models)
{
   var action = new ActionBlock<Model>(

      // your async method
      model => VerifyWebAppUrl(model),

      //some options
      new ExecutionDataflowBlockOptions()
      {
         // CancellationToken = sometoken,
         // pick as many as your system can handle
         MaxDegreeOfParallelism = 100,

         // doesn't need to be ordered 
         EnsureOrdered = false,

         // slight performance tweak, there is only one
         SingleProducerConstrained = true  
      });

   // start
   foreach (var model in models)
      action.Post(model);

   // mark it as completed
   action.Complete();

   // wait for it to finish
   await action.Completion;

   // filter the results
   return models.Where(x => x.ChangeOfStatus).ToList();

}

异步方法

public async Task<Model> VerifyWebAppUrl(Model model)
{
   try
   {
      var request = (HttpWebRequest)WebRequest.Create(model.URL);
      using (var response = (HttpWebResponse) await request.GetResponseAsync())
      {
         if (response.StatusCode != HttpStatusCode.OK && model.Status == "A")
            model.ChangeOfStatus = true;
         if (response.StatusCode == HttpStatusCode.OK && model.Status != "A")
            model.ChangeOfStatus = true;
      }
   }
   catch (Exception ex)
   {
      // this looks suspicious
      model.ChangeOfStatus = false;
   }
   return model;
}

注意 :这完全未经测试,仅是一个示例