欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

关于Paralle.For的求和问题

程序员文章站 2022-03-13 09:18:36
.net4中加入了并行机制——所谓并行就是同时开辟若干个线程来进行计算。这些线程由于都是互相独立的,所以在进行一些分布式(比如各自不同的工作)的时候是非常简单,不过要把这些处...

.net4中加入了并行机制——所谓并行就是同时开辟若干个线程来进行计算。这些线程由于都是互相独立的,所以在进行一些分布式(比如各自不同的工作)的时候是非常简单,不过要把这些处理结果汇总起来却不是那么容易——下面来看一个非常简单的例子(求1~1000的和)。
如果你尝试使用以下的代码计算,恐怕令你大跌眼镜!
[c#]
int sum = 0;
parallel.for(0, 1000,i => {sum+=i;});
[vb.net]
dim sum as integer = 0
parallel.[for](0, 1000, function(i)
sum += i)
究其原因就是.net会默认开辟一些线程同时进行“sum+=i”的计算。那么由于sum被这些线程同时使用,往往是一个线程还没有处理完毕,另外一个线程又介入了,自然无法得到正确结果了。
解决这个问题的办法有许多:
【一】分解法:
所谓分解法,就是针对“同一个变量”被不同线程“共享”这一诟病而提出的。——也就是说,把1~1000求和分成若干块进行处理(等于给每一个线程分配了不同的内存)。最后把分布计算的结果进行累计汇总即可。结果如下:
[c#]
int[] numbers = enumerable.range(1, 1000).toarray();
int[] values=new int[4];
int sum = 0;
parallel.for(0, 4, i => { values[i] = new program().gettotal(i * 250, 250, numbers); });
sum = values.sum();
console.writeline(sum);
[vb.net]
 
dim numbers as integer() = enumerable.range(1, 1000).toarray()
dim values as integer() = new integer(3) {}
dim sum as integer = 0
parallel.[for](0, 4, function(i)
values(i) = new program().gettotal(i * 250, 250, numbers))
sum = values.sum()
console.writeline(sum)
 
【二】使用静态变量
静态变量本身就具备“同步”的能力(这种例子在简单工厂中也可以窥见)。所以这里显然可以使用,代码如下:
[c#]
 
public class program
        {
            static int sum = 0;
            static void main(string[] args)
            {
                parallel.for(1, 1001, i => {sum+=i;});
                console.writeline(sum);
            }
        }
 
[vb.net]
 
public class program
    shared sum as integer = 0
    private shared sub main(args as string())
        parallel.[for](1, 1001, sub(i)
        sum += i)
        console.writeline(sum)
    end sub
end class
 
【三】使用volatile变量(一般编译器为了优化性能,往往把常用的变量复制一份到寄存器中,然后直接对寄存器进行操作,等到操作完毕之后再写回原来的内存中。多线程会导致寄存器中的变量不同步,所以结果也不对。而volatile就是告诉编译器直接从内存中读取那个数字进行操作,而不是拷贝到寄存器之后处理):
[c#]
 
public class program
        {
            volatile int sum = 0;
            public void showresult()
            {
                parallel.for(1, 1001, i => { sum+=i; });
                console.writeline(sum);
            }

            static void main(string[] args)
            {
                program p = new program();
                p.showresult();
            }
        }
 
[vb.net,由于vb.net没有此特性,所以使用thread.volitaleread每次读取最新的数值后进行累加]
 
public class program
    dim sum as integer = 0
    public sub showresult()
        parallel.for(1, 1001, sub(i)
                                  thread.volatileread(sum)  '总是读取最新数值
                                  sum = sum + i
                                  thread.sleep(2)
                              end sub)
        console.writeline(sum)
    end sub

    public shared sub main(args as string())
        dim p as new program()
        p.showresult()
    end sub
end class
 
【四】使用lock(锁住一个变量,然后直到该线程操作完毕自动释放变量,另外一个线程进来操作……如此反复而已):
[c#]
 
 public class program
        {
            int sum = 0;
            public void showresult()
            {
                object obj = new object();
                parallel.for(1, 1001, i => { lock (obj) { sum += i; thread.sleep(10); } });
                console.writeline(sum);
            }

            static void main(string[] args)
            {
                program p = new program();
                p.showresult();
            }
        }
 
[vb.net]
 
public class program
    private sum as integer = 0
    private obj as new object
    public sub showresult()
        dim obj as new object()
        parallel.for(1, 1001, sub(i)
                                  synclock obj
                                      sum = sum + i
                                  end synclock
                              end sub)
                                  console.writeline(sum)
    end sub
end class

module m
    sub main()
        dim p as new program
        p.showresult()
    end sub
end module
 
【五】使用internlock函数:
[c#]
 
 public class program
        {
            int sum = 0;
            public void showresult()
            {
                parallel.for(1, 1001, i => { interlocked.add(ref sum, i); });
                console.writeline(sum);
            }

            static void main(string[] args)
            {
                program p = new program();
                p.showresult();
            }
        }
 
[vb.net]
 
public class program
    private sum as integer = 0
    public sub showresult()
        parallel.[for](1, 1001, sub(i)
                                    interlocked.add(sum, i)
                                end sub)
        console.writeline(sum)
    end sub

    shared sub main(args as string())
        dim p as new program()
        p.showresult()
    end sub
end class

 

 

摘自 serviceboy