热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

DotNet并行计算使用误区(三)

   这篇文章主要是从实用的角度讲解并行计算需要了解的一些基础知识以及需要注意的地方,包括并行循环的方法、如何终止、线程安全、常用类型等几方面。关于TPL中提供的并行方法,这里就不

    这篇文章主要是从实用的角度讲解并行计算需要了解的一些基础知识以及需要注意的地方,包括并行循环的方法、如何终止、线程安全、常用类型等几方面。

关于TPL中提供的并行方法,这里就不再多说了,网上有很多例子,本系列文章第三个Topic主要讲的不是“如何跑”,而是要讲一下“如何停”。

    曾经查过很多关于二者的资料,可能是我理解的原因,总觉得很少有对其解释正确的,所以我觉得还是有必要写出我的观点,请大家指正。

    Section 1.并行循环的终止:Break与Stop

    关于二者网上有很多解释,很多人都认为,在并行计算中:

    1.Break的调用会导致当前任务和已分配任务的终止

    2.Stop的调用会导致当前任务的终止

    本人对以上两点持怀疑态度,经过试验证明,Break和Stop并不像以上说的那样。

    这里先解释一下名词,“当前任务”指的是当前已经触发Break(Stop)条件的那个任务;“已分配任务”指的是与“当前任务”并行执行的任务;“未分配任务”指尚未开始的循环部分。

    有以下测试代码,这些代码在不同核数量的机器上返回的记录数是不同的,这一点待会再说,先看代码:

class Program

{

static List<int> Data = new List<int>();

static ParallelOptions opt = new ParallelOptions();


static void Main(string[] args)

{

opt.MaxDegreeOfParallelism
= Environment.ProcessorCount;


for (int i = 0; i < 10; i++)

{

Data.Add(i);

}


Console.WriteLine(
"CPU Degree:" + opt.MaxDegreeOfParallelism);

Console.WriteLine(
"GeneralFor Result:");

new Program().GeneralFor();

Console.WriteLine(
"ParallerStop Result:");

new Program().ParallerStop();

Console.WriteLine(
"ParallelBreak Result:");

new Program().ParallelBreak();


Console.Read();

}

//一个普通的For循环

private void GeneralFor()

{

for (int i = 0; i < Data.Count; i++)

{

if (Data[i] > 5)

break;


Console.WriteLine(Data[i]);

}

}

//并行计算的Stop

private void ParallerStop()

{

Parallel.For(
0, Data.Count,opt, (i, LoopState) =>

{

if (Data[i] > 5)

LoopState.Stop();

Thread.Sleep(
10);


Console.WriteLine(Data[i]);

});

}

//并行计算的Break

private void ParallelBreak()

{

Parallel.For(
0, Data.Count, opt, (i, LoopState) =>

{

if (Data[i] > 5)

LoopState.Break();

Thread.Sleep(
10);


Console.WriteLine(Data[i]);

});

}

}

 

    下图分别是程序在2(32#)、4(64#)、48(64#)核CPU下运行的结果:

DotNet并行计算使用误区(三)

  

    个人认为,不同CPU核数量对于使用Break与Stop终止循环形式的最终记录返回数量是有影响的,即这会影响TPL分配任务的方针,TPL在运行时才会“源源不断”的分配任务,开启的线程数也是递增形式的。(最大线程数应该有限制,具体是多少不确定,有的说是64也有的说是256,等待高人解答)

    所以,对于Stop与Break,我的观点是,在并行任意任务中调用Stop方法,则会终止除当前任务外的所有并行任务(包括未分配的和已分配的),返回最终结果,而不是像传说的那样,终止了当前任务;Break只会停止继续分配新任务,并不影响当前任务的和已经分配的并行任务的执行,而且同样不会终止当前任务。

    Stop更改ParallelLoopState 对象的 IsStop值为true;

    Break更改ParallelLoopState 对象的 LowestBreakIteration 属性值等于 true 。
  
 

未分配的任务(未开始的任务)

已分配的任务(并行中的任务)

当前任务(触发条件的那个任务)

单行中的Break

停止分配

停止执行(相当于“当前任务”)

停止执行

Break

停止分配

继续执行

继续执行

Stop

停止分配

停止执行

继续执行

 

    如上图中显示,调用Stop后,结果中只能可能有一个大于5的结果,因为此时未分配和已分配的任务都被终止了,而当前任务并没有停止,继续执行打印语句,打印出来的只是当前的那个大于5的任务;

    而调用Break后,结果中大于5的结果数量不定,因为当当前任务因满足大于5的条件,而触发Break后,其他已分配的任务并不会停止,即使它们包含大于5的任务,同样也会打印出来,这就是上图中第三幅图中,Break任务出现两个大于5的结果的原因!

    Stop和Break,它们的区别可以用下图表示:

DotNet并行计算使用误区(三)

    图中实现表示运行的任务,虚线表示任务运行过程中被终止。

    Section 2.线程安全

    在并行计算中应当使用线程安全的类,例如有些时候我们需要不断迭代形成一个集合组织,这个集合可能是一个列表,在普通程序中List完全可以完成这个任务,但是如果在并行计算中使用List的add方法,就会出现一些错误,这些错误是随机的,也就是说有时候并不出现。

    以下代码:

List<string> ls = new List< string >();

Parallel.For(
0, 10000, (i) =>

{

ls.Add(i.ToString());

});

    以上代码偶尔会出现错误,出现错误的概率随着循环次数和并行任务的增加而增大,类似代码需求可以使用ConcurrentBag来代替,针对并行计算提供的类库请参照MSDN:http://msdn.microsoft.com/zh-cn/library/dd287108.aspx

    提示:并行计算并不是天上掉下的馅饼,它不是所有时候都比串行程序快,因为并行总要付出一些额外的代价,比如任务分配、任务同步、任务通讯等,到底什么时候才能放心的吃掉这个馅饼,需要仔细地设计算法,并且应该在多台典型的服务器环境中进行测试、对比,这是一个比较烦人的过程,但是最终得到的结果可能会改变你的设计思路。

 

具体可以参考我的文章:

DotNet并行计算的使用误区(一)

http://www.cnblogs.com/isline/archive/2011/04/20/2022228.html

DotNet并行计算的使用误区(二)

http://www.cnblogs.com/isline/archive/2011/04/21/2023137.html


推荐阅读
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
author-avatar
铁狼爷们儿
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有