并发编程概述
最近学习C#的并发编程,顺便做些笔记,既能加深对知识的理解,又能做些分享,并发不是什么新概念,N多年前就有了,大到服务器端程序,小到桌面客户端应用,并发编程都有用武之地。
- 服务端的大型程序需要响应大量的客户端数据请求,所以要充分考虑并发。
- 桌面等客户端应用,因为面向最终用户,程序必须做到即时影响,才能带来很好的体验,这也十分依赖并发。
1. 并发
通俗的讲,并发就是同时做很多任务,实现并发有很多方式,比如多线程,异步,响应是编程,函数式编程,数据流等,都可以实现并发编程。
2. 多线程
多线程是实现并发的一种形式,它采用多个线程来执行程序,是一种最古老最原始的实现并发的方式。
线程是一个独立的运行单元,每个进程内部都可能有多个线程,每个线程可以各自同时执行指令,都有自己独立的栈,并与进程内的其他线程共享内存。
3. 线程池
每个.Net程序都有一个线程池,线程池维护着一定数量的工作线程,这些线程等待着程序分配下来的任务,并且线程池随时监控着线程的数量,它的参数多达数十个,但我们一般采用默认的设置。默认设置一般都是经过精心设计并仔细调整过的,适用于绝大多数现实中的应用场景。
4. 并行处理
4.1 并行处理的定义
把正在执行的任务分成很多小任务,分配给多个同时运行的线程,并让他们在不同的CPU核心上独立运行,就是并行处理。并行处理是多线程的一种,而多线程是并发的一种。
4.2 并行处理的场景
如果程序中有大量的计算任务,并且这个任务能分割成若干个相互独立的小任务,那就应该使用并行编程,并行编程可以提高CPU的运用效率,可以提高吞吐量,适用于大量的CPU密集型运算任务,尤其在现在的多核CPU中。
4.3 并行处理的形式
并行的形式分两种:
- 数据并行,指有的大量的数据需要处理,并且每一块数据的处理过程都是彼此独立的
- 任务并行,指有大量的任务需要执行,并且每个任务的执行过程基本都是彼此独立的
5. 异步编程
5.1 异步编程定义
异步编程是并发的一种形式,老式的异步编程采用回调的机制,以避免创建不必要的线程。异步编程的核心概念是异步操作,即启动的操作会在一定时间后才能完成,这个操作正在执行,却并不会阻塞原来的线程,启动了这个操作的线程还可以继续执行其他任务,等操作完成时,它会调用回调函数,已让程序知道操作已经结束了。
5.2 应用场景
- 对于客户端扥面向终端用户的GUI,即用户界面类型的程序,异步可以提高操作的界面响应能力,不会出现临时锁定界面的情况,程序在执行任务时,不影响用户进行其他输入操作
- 对于服务端程序来讲,异步编程可以提高扩展性,从而纵向扩展服务端应用的并发能力,接收更多的请求。
5.4 异步与多线程的区别
线程就是实现异步的一个方式,异步是让调用方法的主线程不需要同步等待另一线程的完成,从而可以让主线程干其它的事情。 异步和多线程并不是一个同等关系,异步是最终目的。多线程只是我们实现异步的一种手段。异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情。实现异步可以采用多线程技术或者交给另外的进程来处理。 如果都是独占cpu 的业务, 在单核情况下多线程和单线程没有区别。
5.5 同步的概念
同步是指,进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系。即前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。 其中并发又有伪并发和真并发,伪并发是指单核处理器的并发,真并发是指多核处理器的并发。
6. 响应编程
响应编程是另一种形式的并发编程,它基于异步事件,而不是异步编程中的异步操作,异步操作有一个开始执行的概念,但是异步事件可以在任何时间发生,并且可以发生多次,大概类似于用户响应事件的概念。
它是一种声明式的编程模式,程序在该模式中对事件做出与之对应的响应。
7. 函数式编程
大多数并发编程,其本质都是函数式的,函数式编程有两个原则,一个是简洁,有非常清晰的输入和输出,而且尽可能的避免全局或者共享变量。另一个原则就是不变性,指一段数据不能被修改,程序永远不需要对这些数据进行同步,就是非常简单的输入数据,输出数据。