锁定老帖子 主题:多线程是个不靠谱的东西
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-05-06
首先我排除了大部分的文件读写操作,顺序读取会导致文件指针的移动,这显然会导致不确定数据结果,特别是要把数据填充到一系列结构(Struct)中去的时候,多线程产生了一堆错误的结果。 其次内存中数据操作似乎也不好确定是否该用多线程,线程的生产、切换、消费都要消耗时间,在single core的机器上,多线程只会更没效率而不是更有效率。对于multi core的机器呢。。。情况似乎变得复杂,线程时间片和操作时间片的长度似乎是一个很关键的因素。对于“短”操作来说,花在线程消费上的开销,远远大于起并行带来的时间减少,因此,多线程只会更慢,而不是更快。但难点是,如何找到一个临界点,以作为是否引入多线程操作的阀值? 线程消费的开销,可能随着机器的情况而变化,包括CPU的usage,CPU的核心数目。。。。 我翻了MC#(multi core C#),PLinq,Parallel C#,谁也没告诉我答案,我们不缺工具,但缺best practise 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-05-06
Parallel.For的实现
public delegate void ForDelegate(int i); public delegate void ThreadDelegate(); public class Parallel { /// <summary> /// Parallel for loop. Invokes given action, passing arguments /// fromInclusive - toExclusive on multiple threads. /// Returns when loop finished. /// </summary> public static void For(int fromInclusive, int toExclusive, ForDelegate action) { // ChunkSize = 1 makes items to be processed in order. // Bigger chunk size should reduce lock waiting time and thus // increase paralelism. int chunkSize = 4; // number of process() threads int threadCount = Environment.ProcessorCount; int cnt = fromInclusive - chunkSize; // processing function // takes next chunk and processes it using action ThreadDelegate process = delegate() { while (true) { int cntMem = 0; lock (typeof(Parallel)) { // take next chunk cnt += chunkSize; cntMem = cnt; } // process chunk // here items can come out of order if chunkSize > 1 for (int i = cntMem; i < cntMem + chunkSize; ++i) { if (i >= toExclusive) return; action(i); } } }; // launch process() threads IAsyncResult[] asyncResults = new IAsyncResult[threadCount]; for (int i = 0; i < threadCount; ++i) { asyncResults[i] = process.BeginInvoke(null, null); } // wait for all threads to complete for (int i = 0; i < threadCount; ++i) { process.EndInvoke(asyncResults[i]); } } |
|
返回顶楼 | |
发表时间:2008-05-06
从开发应用程序的角度来看 是否需要多线程跟应用环境有关 跟核心的多少无关
多线程的瓶颈在于切换上下文和锁 >>首先我排除了大部分的文件读写操作,顺序读取会导致文件指针的移动 >>特别是要把数据填充到一系列结构(Struct)中去的时候,多线程产生了一堆错误的结果 如果这种错误你都要犯,我只能说两点: 1 你不知道怎么合理使用锁 2 你不知道文件系统是怎么运作的 有空看看filesystem的科普文章吧,或者看看linux是怎么维护filenode的 而且,你这帖子属于文不对题,内容分明是在说:我不会用多线程 |
|
返回顶楼 | |
发表时间:2008-05-06
seen 写道 从开发应用程序的角度来看 是否需要多线程跟应用环境有关 跟核心的多少无关
多线程的瓶颈在于切换上下文和锁 >>首先我排除了大部分的文件读写操作,顺序读取会导致文件指针的移动 >>特别是要把数据填充到一系列结构(Struct)中去的时候,多线程产生了一堆错误的结果 如果这种错误你都要犯,我只能说两点: 1 你不知道怎么合理使用锁 2 你不知道文件系统是怎么运作的 有空看看filesystem的科普文章吧,或者看看linux是怎么维护filenode的 而且,你这帖子属于文不对题,内容分明是在说:我不会用多线程 事实上,他说的问题极端重要。如果一种并行设施无法平滑的从顺序代码进行迁移,那么就没有什么太大的价值.你从顺序型的代码写好一个程序,当你要把它们并行化的时候居然发现要从新推倒从来,那几乎是不可想象的.因为直接针对并行开发应用的代价是非常昂贵的。当你在编写业务逻辑的时候提前考虑并行问题无疑就是引入复杂性,这就如C/C++里一边写业务逻辑一边要考虑内存和指针,是一种极大的负担.但是当你完成业务逻辑以后,通过并行来提升效率就提升到了第一位,但是这个时候如果再把业务牵扯进来,又会引发极大的混乱。 引用 首先我排除了大部分的文件读写操作,顺序读取会导致文件指针的移动,这显然会导致不确定数据结果,特别是要把数据填充到一系列结构(Struct)中去的时候,多线程产生了一堆错误的结果。
像类似这种问题,如果不从语言设施特别是类型系统上进行根本的改观,只是依靠加入特定的并行补丁毫无疑问是一种极大的灾难.最生动的例子,想想C++里面再不引入GC的前提下引入exception,这种脑残设计的会导致什么后果. |
|
返回顶楼 | |
发表时间:2008-05-06
seen 写道 从开发应用程序的角度来看 是否需要多线程跟应用环境有关 跟核心的多少无关
多线程的瓶颈在于切换上下文和锁 >>首先我排除了大部分的文件读写操作,顺序读取会导致文件指针的移动 >>特别是要把数据填充到一系列结构(Struct)中去的时候,多线程产生了一堆错误的结果 如果这种错误你都要犯,我只能说两点: 1 你不知道怎么合理使用锁 2 你不知道文件系统是怎么运作的 有空看看filesystem的科普文章吧,或者看看linux是怎么维护filenode的 而且,你这帖子属于文不对题,内容分明是在说:我不会用多线程 你不过是在犯傻而已. 线程是什么,CPU的时间片而已. 对于单核或者单CPU来说,线程是什么? CPU时间的轮换而已,CPU时间片的轮换必然带来开销,所以对于单核来说同样Print out一个List里的data, 多线程的速度会远比单线程慢,而多核系统,好处是两个线程可以被安排到两个核心上,才有可能加速处理玩List里的Data,(如果不是Print out这样简单的东西,而是FF变换). 第二,你压根国文就不及格.我说的是读取一系列Struct结构,文件的构成是包含的是: (Struct A)(Struct B)(Struct B)(Struct C)..... 无法使用多线程是因为Struct B的文件读取位置,受到Struct A Size的限制. 你这样傻,我为什么还要和你解释呢? |
|
返回顶楼 | |
发表时间:2008-05-06
Trustno1 写道 像类似这种问题,如果不从语言设施特别是类型系统上进行根本的改观,只是依靠加入特定的并行补丁毫无疑问是一种极大的灾难.最生动的例子,想想C++里面再不引入GC的前提下引入exception,这种脑残设计的会导致什么后果.
如何将顺序结构切换成并行结构是一个难点...而什么时候该实施结构转换,是难点的难点. 我利用Parallel处理Assmebly结构,单核上要比顺序结构慢20%,双核机器上比顺利结构快5%...只能说,并行得还不够啊!!! |
|
返回顶楼 | |
发表时间:2008-05-06
WALL.E 写道 引用 事实上,他说的问题极端重要。如果一种并行设施无法平滑的从顺序代码进行迁移,那么就没有什么太大的价值.你从顺序型的代码写好一个程序,当你要把它们并行化的时候居然发现要从新推倒从来,那几乎是不可想象的.因为直接针对并行开发应用的代价是非常昂贵的。当你在编写业务逻辑的时候提前考虑并行问题无疑就是引入复杂性,这就如C/C++里一边写业务逻辑一边要考虑内存和指针,是一种极大的负担.但是当你完成业务逻辑以后,通过并行来提升效率就提升到了第一位,但是这个时候如果再把业务牵扯进来,又会引发极大的混乱。 说这话没有理由。顺序代码凭什么应该顺利地迁移到并行代码?除非编写的时候就为并行优化,顺序代码一般都严重依赖上下文关系。打破这个关系自然跟重写没什么区别。 传闻IBM花了大量时间研制并行编译器。如果顺序代码都可以顺利地转化成并行代码,那这个东西早就搞出来了。而且PS3也不会弄得现在这样子。 话是不能说的那么绝对滴..... 引用 如何将顺序结构切换成并行结构是一个难点...而什么时候该实施结构转换,是难点的难点.
我利用Parallel处理Assmebly结构,单核上要比顺序结构慢20%,双核机器上比顺利结构快5%...只能说,并行得还不够啊!!! 俗话说,只有想不到,没有做不到. 赫赫. |
|
返回顶楼 | |
发表时间:2008-05-06
WALL.E 写道 说这话没有理由。顺序代码凭什么应该顺利地迁移到并行代码?除非编写的时候就为并行优化,顺序代码一般都严重依赖上下文关系。打破这个关系自然跟重写没什么区别。
传闻IBM花了大量时间研制并行编译器。如果顺序代码都可以顺利地转化成并行代码,那这个东西早就搞出来了。而且PS3也不会弄得现在这样子。 就是因为我们编程能力已经落后于硬件的进步了.大部分时候,我们都是用顺序的方式去思考逻辑. 我的想法并不是要完全打破顺序结构,而是在顺序结构适当中引入并行结构. 比如从文件中读数据--->对每个数据进行傅立叶变换--->把结果保存到文件中. 就可以用顺序--->并行--->顺序的方式来执行. 我想从现在到未来,CPU的数目只会更多, 昨天送来的样机有2个4核CPU 加 两张 2个双核 GPU, 12个core让你使用,并行只会更重要..... |
|
返回顶楼 | |
发表时间:2008-05-06
Trustno1 写道 seen 写道 从开发应用程序的角度来看 是否需要多线程跟应用环境有关 跟核心的多少无关
多线程的瓶颈在于切换上下文和锁 >>首先我排除了大部分的文件读写操作,顺序读取会导致文件指针的移动 >>特别是要把数据填充到一系列结构(Struct)中去的时候,多线程产生了一堆错误的结果 如果这种错误你都要犯,我只能说两点: 1 你不知道怎么合理使用锁 2 你不知道文件系统是怎么运作的 有空看看filesystem的科普文章吧,或者看看linux是怎么维护filenode的 而且,你这帖子属于文不对题,内容分明是在说:我不会用多线程 事实上,他说的问题极端重要。如果一种并行设施无法平滑的从顺序代码进行迁移,那么就没有什么太大的价值.你从顺序型的代码写好一个程序,当你要把它们并行化的时候居然发现要从新推倒从来,那几乎是不可想象的.因为直接针对并行开发应用的代价是非常昂贵的。当你在编写业务逻辑的时候提前考虑并行问题无疑就是引入复杂性,这就如C/C++里一边写业务逻辑一边要考虑内存和指针,是一种极大的负担.但是当你完成业务逻辑以后,通过并行来提升效率就提升到了第一位,但是这个时候如果再把业务牵扯进来,又会引发极大的混乱。 引用 首先我排除了大部分的文件读写操作,顺序读取会导致文件指针的移动,这显然会导致不确定数据结果,特别是要把数据填充到一系列结构(Struct)中去的时候,多线程产生了一堆错误的结果。
像类似这种问题,如果不从语言设施特别是类型系统上进行根本的改观,只是依靠加入特定的并行补丁毫无疑问是一种极大的灾难.最生动的例子,想想C++里面再不引入GC的前提下引入exception,这种脑残设计的会导致什么后果. 我觉得你想说的其实是:除非语言设施支持并发,不然并发编程是很容易引起混乱的,是代价昂贵的。 假设我猜对了,那我的感觉是,这话听起来很像另外一个常见的看法:除非语言设施屏蔽指针,不然内存操作是很容易引起混乱的,是代价昂贵的。 话说回来,并发的难度比指针的难度要高多了。但世界上用c写的并发的应用并不都是失败的。 |
|
返回顶楼 | |
发表时间:2008-05-06
引用 话说回来,并发的难度比指针的难度要高多了。但世界上用c写的并发的应用并不都是失败的。
这要注意上下文的语境了. 成功!=开发低成本. |
|
返回顶楼 | |