2017-01-25 185 views
2

我有一个问题,停止每个循环的并行。停止Parallel.ForEach立即

我遍历了从表中检索到的大约40.000条DataRows的集合,当我的结果集中有100个条目时,我需要立即停止我的循环。问题是,当我在ParallelLoopState上触发Stop方法时,迭代不会立即停止,从而导致结果集中的不一致(对于少量或多个项目)。

我没有办法确定,只要我停下来,我杀死所有线程?

List<DataRow> rows = new List<DataRow>(dataTable.Select()); 
    ConcurrentDictionary<string, object> resultSet = new ConcurrentDictionary<string, object>(); 

    rows.EachParallel(delegate (DataRow row, ParallelLoopState state) 
    { 
    if (!state.IsStopped) 
    { 
     using (SqlConnection sqlConnection = new SqlConnection(Global.ConnStr)) 
     { 
     sqlConnection.Open(); 

     //{ 
     // Do some processing....... 
     //}  

     var sourceKey = "key retrieved from processing"; 
     if (!resultSet.ContainsKey(sourceKey)) 
     { 
      object myCustomObj = new object(); 

      resultSet.AddOrUpdate(
      sourceKey, 
      myCustomObj, 
      (key, oldValue) => myCustomObj); 
     } 

     if (resultSet.Values.Count == 100) 
      state.Stop(); 
     } 
    } 
    }); 
+1

*为什么*你想要并行执行SQL命令?这不会使查询运行速度加快。你的*实际*问题是什么? –

+0

在方法 –

+4

中使用锁定BTW 40K行根本没有数据。当你只需要100个加载它们的所有40K时,虽然是一个错误。你为什么不使用'SELECT TOP 100'? –

回答

4

ParallelLoopState.Stop文档页面说明,调用Stop()将阻止新的迭代无法启动。它不会中止任何现有的迭代。

Stop()还将IsStopped财产设置为true。长时间运行的迭代可检查IsStopped的值并在需要时过早退出。

这被称为协作取消,这比中止线程好得多。中止一个线程是昂贵的,并使清理变得困难。想象一下,如果在您想要完成工作时抛出了一个ThreadAbort异常,会发生什么情况。

,另一方面协同取消允许任务commiting或中止交易的必要,关闭连接,清理其他国家和文件等

而且以后正常退出,Parallel使用的任务,而不是线程,来处理数据块。其中一个线程是启动并行操作的原始线程。放弃不会浪费线程池线程,它也会终止主线程。

这是不是一个bug - Parallel是为了解决数据并行性问题,而不是异步执行。在这种情况下,需要系统根据需要使用尽可能多的任务来处理数据,并在处理完成后继续执行。

+0

“这被称为合作取消,这比中止线程好得多 - ”当然......但它并不总是完成同样的事情。如果你的循环体主要由一个需要很长时间的呼叫组成(比如上传一个大文件),那么你的令牌就毫无价值。如果我放弃,我会得到我想要的。 –

+0

@EdS。混淆了异步IO的并行处理。除了异步IO方法* do *支持取消和取消令牌的地方。您无法阻止HTTP服务器发送*数据,您可以停止等待它到达。您可以停止从响应流中读取数据。您可以使用取消令牌在中止后清理连接。使用Thread.Abort –

+0

@EdS不能执行任何这些操作。另外,即使你没有任务,使用*线程来阻塞IO也是浪费。 Win32提供回调,异步IO的完成端口以及等待它们的事件。 –