背景

  发现在.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. convert NameValueCollection/Dictionary<string, object> to JSON string

    public static class WebExtension { public static T Decode<T>(this RequestBase res) { Type type ...

  2. HDU2063_过山车_C++

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2063 又是一道二分图匹配的裸题,直接上匈牙利算法 注意一点它末尾的0结束,是标志着有多组数据……坑…… # ...

  3. Android开发-API指南-<permission-group>

    <permission-group> 英文原文:http://developer.android.com/guide/topics/manifest/permission-group-el ...

  4. 如何绕过CDN找源站ip?

    这是一个总结帖,查了一下关于这个问题的国内外大大小小的网站,对其中说的一些方法总结归纳形成,里面具体发现ip的方法不是原创,所有参考的原贴都也贴在了后面,大家可以自行看看原贴. 首先,先要明确一个概念 ...

  5. 将U盘分成 启动盘+文件存储区

    我看了很多帖子,发现想要将U盘分区的朋友绝大部分是和我一样,想用U盘做成一个启动盘同时兼顾文件存储,分区的目的很简单,就是想将启动部分单独做成一个区,以免在日常的应用中使得启动文件染毒或者误操作造成损 ...

  6. USACO Section 3.3 骑马修栅栏 Riding the Fences

    题目背景 Farmer John每年有很多栅栏要修理.他总是骑着马穿过每一个栅栏并修复它破损的地方. 题目描述 John是一个与其他农民一样懒的人.他讨厌骑马,因此从来不两次经过一个栅栏.你必须编一个 ...

  7. Java学习一

    Java程序的运行机制和JVM     JVM(java 虚拟机) Java Virtual Machine java语言比较特殊,由Java语言编写的程序需要经过编译步骤, JDK java SE ...

  8. 【Struts 2】Struts2环境搭建

    一.关键步骤 1.创建Java Web项目 2.引入Struts2的依赖包,将依赖包拷贝到WEB-INF/lib下 * commons-logging-1.0.4.jar * freemarker-2 ...

  9. C#多线程案例基础

    C#多线程案例基础(转) 在学习多线程之前,我们先来看几个概念: 1,什么是进程?    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源,当然一个程序也可能开 ...

  10. MyBatis学习系列二——增删改查

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring 数据库的经典操作:增删改查. 在这一章我们主要说明一下简单的查询和增删改, ...