如何做parallel.for异步方法

时间:2017-05-09 05:33:45

标签: c# multithreading asynchronous parallel-processing parallel.for

使用某些异步方法在c#中进行并行处理的最佳方法是什么。 让我用一些简单的代码解释

示例场景:我们有一个人和1000个文本文件。我们想检查他的文本文件是否包含敏感关键字,如果他的某个文本文件包含敏感关键字,我们会将其标记为不受信任。检查这个的方法是异步方法,并且我们发现其中一个敏感关键字不需要进一步处理,并且必须为该人打破检查循环。

为了获得最佳性能并使其如此之快,我们必须使用并行处理 简单的psudocode:

boolean sesitivedetected=false;
Parallel.ForEach(textfilecollection,async (textfile,parallelloopstate)=>
{
    if (await hassensitiveasync(textfile))
    {
         sensitivedetected=true;
         parallelloopstate.break()
    }
}
‌if (sensitivedetected)
    markuntrusted(person)

问题是Parallel.ForEach不等到异步任务完成,因此一旦创建任务完成,就会运行语句‌if (sensitivedetected)。 我阅读了其他问题,例如write parallel.for with asyncasync/await and Parallel.For以及许多其他页面。 当您需要在以后收集和使用异步方法的结果时,此主题非常有用,但在我的方案中,应尽快结束循环执行。

更新:示例代码:

        Boolean detected=false;
        Parallel.ForEach(UrlList,  async (url, pls) =>
          {
              using (HttpClient hc = new HttpClient())
              {
                  var result = await hc.GetAsync(url);

                  if ((await result.Content.ReadAsStringAsync()).Contains("sensitive"))
                  {
                      detected = true;
                      pls.Break();
                  }
              }
          });
        if (detected)
            Console.WriteLine("WARNING");

1 个答案:

答案 0 :(得分:0)

实现你需要的最简单的方法(而不是你想要的,因为线程是邪恶的)。是使用ReactiveExtensions。

var firstSensitive = await UrlList
                     .Select(async url => {
                         using(var http = new HttpClient()
                         {
                             var result = await hc.GetAsync(url);
                             return await result.Content.ReadAsStringAsync();
                         }
                     })
                     .SelectMany(downloadTask => downloadTask.ToObservable())
                     .Where(result => result.Contains("sensitive"))
                     .FirstOrDefaultAsync();

if(firstSensitive != null)
    Console.WriteLine("WARNING");

限制并发HTTP查询的数量:

int const concurrentRequestLimit = 4;
var semaphore = new SemaphoreSlim(concurrentRequestLimit);
var firstSensitive = await UrlList
                     .Select(async url => {
                         await semaphore.WaitAsync()
                         try
                         using(var http = new HttpClient()
                         {
                             var result = await hc.GetAsync(url);
                             return await result.Content.ReadAsStringAsync();
                         }
                         finally
                             semaphore.Release();
                     })
                     .SelectMany(downloadTask => downloadTask.ToObservable())
                     .Where(result => result.Contains("sensitive"))
                     .FirstOrDefaultAsync();

if(firstSensitive != null)
    Console.WriteLine("WARNING");