背景

  发现在.Net领域领域中,多线程的处理大致经历了这么几个阶段:

  Thread→ThreadPool→委托的异步调用→Task→TaskFactory→Parallerl→异步编程模型(async和await)。

线程进程、多线程

1.什么是线程?线程和进程的区别是什么?

  进程是操作系统对一个正在运行的程序的抽象。操作系统会记录每一个进程的状态,这些状态就称作进程的上下文。这些状态主要包括了PC,寄存器以及主存的当前内容。

  当操作系统在进程间切换的时候,也会切换相应的上下文,从而保证进程恢复到之前的状态。

  在进程当中,又被计算机界的大神们引入了线程的概念,这些线程可以共享进程级的代码与数据,这种共享一般比进程间的共享更加高效。

  线程是程序执行的最小单元。

  区别: 进程是操作系统进行资源处理和分配的最小单位,而一个进程可以包含多个线程,并共享进程的资源。

2.什么是多线程?为什么设计多线程?

  多线程指的是一个进程可以包含多个并发的线程(同一个时刻只有一个线程运行)。例如酷狗,我们可以一边听歌一边搜索自己喜欢的歌曲。

多线程的存在能够让进程及时处理我们多项的请求,提高应用程序的利用率。

  多线程编程需要了解到多线程运行面临的问题:

1)既然一个进程的多个线程共享进程的资源,怎样保证有多个线程访问同一资源时单个线程的访问不受其它线程的干扰。这是线程安全问题。

2)多线程怎么控制线程的执行顺序,这是线程调度问题。

3.什么是主线程

每一个Windows进程都恰好包含一个用作程序入口点的主线程。进程的入口点创建的第一个线程被称为主线程。.Net执行程序(控制台、Windows Form、Wpf等)使用Main()方法作为程序入口点。当调用该方法时,主线程被创建。

4.什么是工作者线程

由主线程创建的线程,可以称为工作者线程,用来去执行某项具体的任务。

5.什么是前台线程

默认情况下,使用Thread.Start()方法创建的线程都是前台线程。前台线程能阻止应用程序的终结,只有所有的前台线程执行完毕,CLR才能关闭应用程序(即卸载承载的应用程序域)。前台线程也属于工作者线程。

6.什么是后台线程

后台线程不会影响应用程序的终结,当所有前台线程执行完毕后,后台线程无论是否执行完毕,都会被终结。一般后台线程用来做些无关紧要的任务(比如邮箱每隔一段时间就去检查下邮件,天气应用每隔一段时间去更新天气)。后台线程也属于工作者线程。

并发与并行的区别

  Erlang 之父 Joe Armstrong 用一张5岁小孩都能看懂的图解释了并发与并行的区别

  并发是两个队列交替使用一台咖啡机,并行是两个队列同时使用两台咖啡机,如果串行,一个队列使用一台咖啡机,那么哪怕前面那个人便秘了去厕所呆半天,

后面的人也只能死等着他回来才能去接咖啡,这效率无疑是最低的。

  并发和并行都可以是很多个线程,就看这些线程能不能同时被(多个)cpu执行,如果可以就说明是并行,而并发是多个线程被(一个)cpu 轮流切换着执行。

  行话解释:

  并发:不同代码块交替执行的性能

  并行:不同代码块同时执行的性能

System.Threading

System.Threading命名空间下的Thread类提供了线程的基本操作。 通过创建一个Thread对象,并执行它的Start()方法,可以新建并运行一个新的线程。

后台线程不会影响应用程序的终结,当所有前台线程执行完毕后,后台线程无论是否执行完毕,都会被终结。一般后台线程用来做些无关紧要的任务(比如邮箱每隔一段时间就去检查下邮件,天气应用每隔一段时间去更新天气)。后台线程也属于工作者线程。

 //主线程入口
static void Main(string[] args)
{
Console.WriteLine("主线程开始!"); //创建前台工作线程
Thread t1 = new Thread(Task1);
t1.Start(); //创建后台工作线程
Thread t2= new Thread(new ParameterizedThreadStart(Task2));
t2.IsBackground = true;//设置为后台线程
t2.Start("传参");
} private static void Task1()
{
Thread.Sleep();//模拟耗时操作,睡眠1s
Console.WriteLine("前台线程被调用!");
} private static void Task2(object data)
{
Thread.Sleep();//模拟耗时操作,睡眠2s
Console.WriteLine("后台线程被调用!" + data);
}

执行发现,【后台线程被调用】将不会显示。因为当所有的前台线程执行完毕后,应用程序就关闭了,不会等待所有的后台线程执行完毕,所以不会显示。

ThreadPool(线程池)

线程池是为突然大量爆发的线程设计的,通过有限的几个固定线程为大量的操作服务,减少了创建和销毁线程所需的时间,从而提高效率,这也是线程池的主要好处。

ThreadPool适用于并发运行若干个任务且运行时间不长且互不干扰的场景。

还有一点需要注意,通过线程池创建的任务是后台任务。

 //主线程入口
static void Main(string[] args)
{
Console.WriteLine("主线程开始!");
//创建要执行的任务
WaitCallback workItem = state => Console.WriteLine("当前线程Id为:" + Thread.CurrentThread.ManagedThreadId); //重复调用10次
for (int i = ; i < ; i++)
{
ThreadPool.QueueUserWorkItem(workItem);
}
Console.ReadLine();
}

System.Threading.Tasks

Task类是封装的一个任务类,内部使用的是ThreadPool类。

.Net 4.0引入了System.Threading.Tasks,简化了我们进行异步编程的方式,而不用直接与线程和线程池打交道。

System.Threading.Tasks中的类型被称为任务并行库(TPL)。TPL使用CLR线程池(说明使用TPL创建的线程都是后台线程)自动将应用程序的工作动态分配到可用的CPU中。

1.Parallel并行编程可以让我们使用极致的使用CPU。并行编程与多线程编程不同,多线程编程无论怎样开启线程,也是在同一个CPU上切换时间片。而并行编程则是多CPU核心同时工作。耗时的CPU计算操作选择并行是明智的。通常情况,每个CPU核心代表一个硬件线程,但超线程技术,可以使一个cpu核心具有两个硬件线程。软件线程顾名思义就是我们在程序中所开启的。

能用Parallel.For的地方就不要用Parallel.ForEach

  class Program
{
static void Main(string[] args)
{
List<Action> actions = new List<Action>() { Credit, Email }; var result = Parallel.For(, actions.Count, (i) =>
{
actions[i]();
}); Console.WriteLine("执行状态:" + result.IsCompleted); Console.Read();
} static void Credit()
{
Console.WriteLine("****************** 发起信用卡扣款中 ******************"); Thread.Sleep(); Console.WriteLine("扣款成功!");
} static void Email()
{
Console.WriteLine("****************** 发送邮件确认单!*****************"); Thread.Sleep(); Console.WriteLine("email发送成功!");
}
}

2.PLINQ(并行LINQ查询)

为并行运行而设计的LINQ查询为PLINQ。System.Linq命名空间的ParallelEnumerable中包含了一些扩展方法来支持PINQ查询。

 int[] modThreeIsZero = (from num in source.AsParallel()
where num % ==
orderby num descending
select num).ToArray();

3.Task

Task,字面义,任务。使用Task类可以轻松地在次线程中调用方法。

 static void Main(string[] args)
{
Console.WriteLine("主线程ID:" + Thread.CurrentThread.ManagedThreadId);
Task.Factory.StartNew(() => Console.WriteLine("Task对应线程ID:" + Thread.CurrentThread.ManagedThreadId));
Console.ReadLine();
}

  3.1Task.Factory.StartNew无参

 Task.Factory.StartNew(() =>
{
MessageBox.Show("测试StartNew:无参数");
});

  3.2Task.Factory.StartNew一个参数

private void button5_Click(object sender, EventArgs e)
{
int val = ;
Task.Factory.StartNew(a =>
{
MessageBox.Show("测试StartNew:参数值" + (int)a);
}, val);
}

  3.3Task.Factory.StartNew多个参数

string userCode=“”;
string mobile=“”;
Task.Factory.StartNew((p) =>
{
var param = (dynamic)p;
//param.userCode
//param.mobile
}, new { userCode = userCode, mobile = mobile });

4.泛型Task

Task是Task的泛型版本,可以接收一个返回值。

 static void Main(string[] args)
{
Console.WriteLine("主线程ID:" + Thread.CurrentThread.ManagedThreadId);
Task<string> task = Task.Run(() =>
{
return Thread.CurrentThread.ManagedThreadId.ToString();
});
Console.WriteLine("创建Task对应的线程ID:" + task.Result); Console.ReadLine();
}

5.Task.Start()和Task.Factory.StartNew()之间有什么区别?

  区别

实战总结

本文主要梳理了以下几点:

任务Task与并行Parallel本质上内部都是使用的线程池,提供了更丰富的并行编程的方式。

默认创建的Thread是前台线程,创建的Task为后台线程。

ThreadPool创建的线程都是后台线程。

任务并行库(TPL)使用的是线程池技术。

class Program
{
static void Main(string[] args)
{
string codeStr = "D050,B023,E059,B020,E067,A011,B024,I137,E066,B014,A006,C042,A002,D047,D046,C029";
IList<string> resultList = codeStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
int everyCount = ;//4个一组
int total = resultList.Count;//总数
int countThread = (int)Math.Ceiling((double)total / everyCount);//线程个数
IList<List<string>> listTotal = new List<List<string>>();
for (int i = ; i < countThread; i++)
{
List<string> list = new List<string>();
int ct = i * everyCount;
for (int j = ct; j < ct + everyCount; j++)
{
if (j < resultList.Count)
{
string res = resultList[j];
list.Add(res);
}
}
listTotal.Add(list);
}
//第一种多线程调用方式
Parallel.For(, listTotal.Count, (i) =>
{
Console.WriteLine("数组索引{0}对应的那个元素{1}", i, listTotal[i]);
DealData(listTotal[i]);
});
//第二种多线程调用方式
Parallel.ForEach(listTotal, (item) =>
{
DealData(item);
});
//或者
ParallelOptions parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount};
Parallel.ForEach(listTotal,parallelOptions,(item) =>
{
DealData(item);
});
//第三种多线程调用方式
Thread[] array = new Thread[countThread];
for (int i = ; i < array.Length; i++)
{
ParameterizedThreadStart ParStart1 = new ParameterizedThreadStart(DealData);
array[i] = new Thread(ParStart1);
List<string> list = listTotal[i];
array[i].Start(list);
}
for (int i = ; i < array.Length; i++)
{
array[i].Join();
}
//第四种多线程调用方式
Task[] tks = new Task[countThread];
for (int i = ; i < listTotal.Count; i++)
{
tks[i] = new Task(DealData, listTotal[i]);
tks[i].Start();
}
Task.WaitAll(tks);
//第五种多线程调用方式
var listTask = new List<Task>();//存储所有线程任务
foreach (var item in listTotal)//几个细分任务就创建几个线程
{
listTask.Add(Task.Factory.StartNew(() => DealKbaseData(item)));//处理单个线程
//listTask.Add(Task.Factory.StartNew(() => Console.WriteLine("此处直接写逻辑处理代码,则无需考虑因方法封装而带来的参数传递问题")));
}
Task.WaitAll(listTask.ToArray());//等待所有线程处理完毕! Console.ReadLine();
}
/// <summary>
/// 输出
/// </summary>
/// <param name="result"></param>
private static void DealData(object result)
{
foreach (string item in (IList<string>)result)
{
Console.WriteLine(item);
}
}
}

Parallel

 方式一
Parallel.Invoke(() => Task1(), () => Task2(), () => Task3());
方式二
Parallel.Invoke(Task1, Task2, Task3);
方式三
Parallel.Invoke(
() =>
{
Task1();
},
Task2,
delegate () { Task3(); console.write('do someting!');});

收集资料

http://www.cnblogs.com/afei-24/p/6904179.html

https://www.cnblogs.com/jonins/p/9444374.html

.Net并行编程的更多相关文章

  1. C#并行编程系列-文章导航

    菜鸟初步学习,不对的地方请大神指教,参考<C#并行编程高级教程.pdf> 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C# ...

  2. Parallel并行编程初步

    Parallel并行编程可以让我们使用极致的使用CPU.并行编程与多线程编程不同,多线程编程无论怎样开启线程,也是在同一个CPU上切换时间片.而并行编程则是多CPU核心同时工作.耗时的CPU计算操作选 ...

  3. .Net中的并行编程-2.ConcurrentStack的实现与分析

    在上篇文章<.net中的并行编程-1.基础知识>中列出了在.net进行多核或并行编程中需要的基础知识,今天就来分析在基础知识树中一个比较简单常用的并发数据结构--.net类库中无锁栈的实现 ...

  4. .Net中的并行编程-3.ConcurrentQueue实现与分析

    在上文<.Net中的并行编程-2.ConcurrentQueue的实现与分析> 中解释了无锁的相关概念,无独有偶BCL提供的ConcurrentQueue也是基于原子操作实现, 由于Con ...

  5. C#~异步编程再续~大叔所理解的并行编程(Task&Parallel)

    返回目录 并行这个概念出自.net4.5,它被封装在System.Threading.Tasks命名空间里,主要提供一些线程,异步的方法,或者说它是对之前Thread进行的二次封装,为的是让开发人员更 ...

  6. .NET并行编程实践(一:.NET并行计算基本介绍、并行循环使用模式)

    阅读目录: 1.开篇介绍 2.NET并行计算基本介绍 3.并行循环使用模式 3.1并行For循环 3.2并行ForEach循环 3.3并行LINQ(PLINQ) 1]开篇介绍 最近这几天在捣鼓并行计算 ...

  7. C#并行编程之数据并行

    所谓的数据并行的条件是: 1.拥有大量的数据. 2.对数据的逻辑操作都是一致的. 3.数据之间没有顺序依赖. 运行并行编程可以充分的利用现在多核计算机的优势.记录代码如下: public class ...

  8. OpenMP共享内存并行编程详解

    实验平台:win7, VS2010 1. 介绍 平行计算机可以简单分为共享内存和分布式内存,共享内存就是多个核心共享一个内存,目前的PC就是这类(不管是只有一个多核CPU还是可以插多个CPU,它们都有 ...

  9. .NET并行编程1 - 并行模式

    设计模式——.net并行编程,清华大学出版的中译本. 相关资源地址主页面: http://parallelpatterns.codeplex.com/ 代码下载: http://parallelpat ...

  10. 【读书笔记】.Net并行编程(三)---并行集合

    为了让共享的数组,集合能够被多线程更新,我们现在(.net4.0之后)可以使用并发集合来实现这个功能.而System.Collections和System.Collections.Generic命名空 ...

随机推荐

  1. Hadoop有关的网站

    软件下载: http://archive.apache.org hbase对Hadoop的支持矩阵: https://hbase.apache.org/book.html#configuration

  2. 为view添加约束constraints

    在相应要设置约束的view中按住鼠标右键进行拖拽,然后向指定的方向添加约束,如图: 拖拽的时候会显示一条蓝线,如上图所示,然后手指离开鼠标的时候会弹出向对应的约束供添加约束的时候进行使用如图:

  3. mac下的几个命令-黑苹果之路

    涉及一些文件操作的命令: 1.去掉/加上windows下文件的系统.只读.隐藏等属性,用chflags,nounchg/unchg,nohidden/hidden 2.去掉文件的@属性(这个属性经常导 ...

  4. Java中List转数组,必须带个参数

    public static void main(String[] args) { List<String> lst = new ArrayList(); lst.add("赵云 ...

  5. Grunt 插件使用汇总

    最近使用了很多 Grunt 插件,这里把使用 Grunt 中涉及的从开发.代码检查.单元测试.E2E 测试,直到发布所涉及的插件,做一个比较完全的汇总. 环境搭建 1. 创建 Web 前端开发环境 2 ...

  6. mysql的一些心得

    1.unsigned修饰整型 ,既为非负数,用此类型可以增加数据长度! 类型                 大小            范围(有符号)                         ...

  7. Note for Computer Networks_Circuit Switching & Packet Switching

    Packet Switching: - In a packet switched network data is transmitted in blocks(packets), typically l ...

  8. Android开发-API指南-<compatible-screens>

    <compatible-screens> 英文原文:http://developer.android.com/guide/topics/manifest/compatible-screen ...

  9. 用Java开发代理服务器

    基础知识 不管以哪种方式应用代理服务器,其监控HTTP传输的过程总是如下: 步骤一:内部的浏览器发送请求给代理服务器.请求的第一行包含了目标URL. 步骤二:代理服务器读取该URL,并把请求转发给合适 ...

  10. CODEVS 1001 舒适的路线

    思路:先按照速度大小对边排序,再枚举最终路径中的速度最大值,并查集,更新答案 #include<iostream> #include<vector> #include<a ...