C#多线程学习笔记八

.netFramework有一些模型对Task进行了封装

这些类封装了Task,所以可以用这些类来进行并行编程。Parallel称为 平行算法,用白话说,就是为了充分利用电脑多核处理器的优势,使得每隔核心都可以努力干活,不让他们闲着,来提高运行效率。

For

Parallel.For(1, 10, (item) =>
{
    
    
   Console.WriteLine(item);
});

输出结果:并行输出
在这里插入图片描述
我们在并行的时候,可以指定当前有几个线程参与计算,不让所有的thread参与计算,不然CPU占用率过高。

分区计算:假设有100个任务,只用8个线程(与处理器数量有关)去执行:t1 => 0- 11 , t2 => 12-23 …
最后会使用ParallelForReplicatingTask进行处理。不要在Parallel.For中使用break或stop,或许会引入一些不必要的Bug。因为都是并行运行。
使用break或stop,因为线程是并发,所以每个线程分配到的第一个数字如0,12,24…依然会被输出。

不过使用需要注意几点:Parallel 并行处理时 如果涉及到共享资源的话,使用要很小心, 因为并行同时访问共享资源,就会出现不确定的状态,非要使用,可以加锁来解决;Parallel中不管是For还是Foreach,处理都是乱序的,并不是按照顺序来处理,所以要当心;如果列表或者循环次数较少,不建议使用Parallel,因为创建线程资源之类的处理会浪费很多事件和资源;同样,如果内部处理逻辑非常简单,也不建议使用Parallel,因为创建资源的耗费并不值得,比较复杂的处理逻辑,可以考虑Parallel。

For的一些高级重载:
a. 设置最高并行使用线程数量

Parallel.For(1, 10, new ParallelOptions()
{
    
    
   MaxDegreeOfParallelism = Environment.ProcessorCount - 1,
}, (item) =>
{
    
    
   Console.WriteLine(item);
});

b. Parallel.For<int>
假如想做一个并行的从1-99的累计计算

var totalNums = 0;
Parallel.For<int>(1, 100, ()=> {
    
     return 0; },(current,loop,total) => 
{
    
    
   total += (int)current;
   return total;
},(total)=> 
{
    
    
   Interlocked.Add(ref totalNums,total);
});
Console.WriteLine(totalNums);

计算结果4950。
对于

public static ParallelLoopResult For<TLocal>(long fromInclusive, long toExclusive, Func<TLocal> localInit, Func<long, ParallelLoopState, TLocal, TLocal> body, Action<TLocal> localFinally);`

由ILSpy反编译可以看到

val = localInit();
val = body (i, parallelLoopState, val);
localFinally(val);

从此看1-99累加的例子,可得如下结论:localInit()的返回值作为body (i, parallelLoopState, val)中的参数值,body (i, parallelLoopState, val)的返回值,作为localFinally(val)的参数值。()=> { return 0;}得到的0作为total += (int)current;中total的初始值,返回的total继续作为Interlocked.Add(ref totalNums,total);中的参数进行计算。
在这里插入图片描述

ForEach

For只能做一些数组的累计运算,ForEach可以应对一些集合运算。

Dictionary<string, string> dic = new Dictionary<string, string>() 
{
    
    
   {
    
    "?","??"},{
    
    "!","!!"},{
    
    ".",".."},
};
Parallel.ForEach(dic,(item)=> 
{
    
    
   Console.WriteLine(item.Key + ":" + item.Value);
});

Parallel函数第一点就是要分区。

Invoke

Parallel.Invoke(()=> 
{
    
    
   Console.WriteLine("t1:"+ Thread.CurrentThread.ManagedThreadId);
},()=> 
{
    
    
   Console.WriteLine("t2:"+ Thread.CurrentThread.ManagedThreadId);
});

Invoke中的两个委托用的是不同线程。

猜你喜欢

转载自blog.csdn.net/Z960515/article/details/113440800