1. 进程的定义
进程是系统进行资源分配和调度的一个独立单位。
进程拥有自己独立的内存空间,所以进程间数据不共享,创建和销毁进程的开销比较大。
import multiprocessing
import time
def sing():
for i in range(89):
print('----正在唱歌-----')
time.sleep(1)
def dance():
for i in range(3):
print('----正在跳舞-----')
time.sleep(89)
if __name__ == '__main__':
#创建两个进程
p1=multiprocessing.Process(target=sing)
p2=multiprocessing.Process(target=dance)
# 开始执行进程
p1.start()
p2.start()
进程之间通讯
1).queue队列
2).进程池
队列是一种先进先出的存储数据结构,就比如排队上厕所一个道理。两个进程通讯,就是一个子进程往queue中写内容,另一个进程从queue中取出数据。就实现了进程间的通讯了。
创建 queue队列对象
q = multiprocessing.Queue(maxsize)
参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。
返回值q 是队列对象。
- put()方法 ,向队列中存放数据。如果队列已满,此方法将阻塞至有空间可用为止。
- get()返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。
- get_nowait(): 不等待,直接抛出异常
- full()如果q已满,返回为True
- empty() 如果调用此方法时 q为空,返回True。
```python
创建队列
q=multiprocessing.Queue(3)相队列里存放数据
q.put(‘hello’) q.put(123) q.put([1,2,3])获取列表中数据数量
print(q.qsize())判断队列是否存放满了
print(q.full())
获取数据
print(q.get()) print(q.get())
不等待
time.sleep(3) print(q.get_nowait())
<a name="T4wtc"></a>
## 2. 线程的定义
线程是进程的一个实体,是CPU调度和分派的基本单位。<br />线程必须依赖于进程存在。一个进程至少拥有一个线程,叫主线程。而多个线程共享内存,从而极大地提高了运行效率。
<a name="XUmih"></a>
### 如何避免多线程竞争资源
- **加锁**
- **使用队列(queue)**
<a name="7S7V4"></a>
## 3.协程的定义
协程则是程序级别的由程序根据需要自己调度。<br />在一个线程中会有很多函数,我们把这些函数称为子程序,在子程序执行过程中可以中断去执行别的子程序,而别的子程序也可以中断回来继续执行之前的子程序,这个过程就称为协程。<br />协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。
<a name="82PmJ"></a>
### 协程的优点:
- 无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力)
- 无需原子操作锁定及同步的开销
- 方便切换控制流,简化编程模型
- 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
<a name="8ny7V"></a>
### 协程的缺点:
- 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
- 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
<a name="A4uFu"></a>
## 4.进程、线程、协程之间的区别
一个程序至少有一个进程,一个进程至少有一个线程<br />线程是划分尺度较小的进程(资源比进程占用的少),使得多线程程序的并发性高。<br />进程在执行的过程中拥有独立的内存单元,而多个线程共享这块内存空间,从而极大的提高了程序的运行效率。<br />线程不能独立执行,必须依存在进程中。
<a name="dMaWN"></a>
### 定义的不同
- 进程是系统进行资源分配最小单元,线程是调度执行的最小单位。
- 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序执行的需要的cpu资源),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源(主要是内存资源).
<a name="nWlHi"></a>
### 区别
- 一个程序至少有一个进程,一个进程至少有一个线程.
- 线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
- 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
- 线程不能够独立执行,必须依存在进程中
<a name="78102351"></a>
### 优缺点
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
<a name="jAc5u"></a>
## 5.GIL 锁
讲到 Python 中的多线程,就不得不面对 GIL 锁,GIL 锁的存在导致 Python 不能有效地使用多线程实现多核任务,因为在同一时间,只能有一个线程在运行。<br />GIL 全称是 Global Interpreter Lock,译为**全局解释锁**。早期的 Python 为了支持多线程,引入了 GIL 锁,用于解决多线程之间数据共享和同步的问题。但这种实现方式后来被发现是非常低效的,当大家试图去除 GIL 的时候,却发现大量库代码已重度依赖 GIL,由于各种各样的历史原因,GIL 锁就一直保留到现在。
<a name="crM4a"></a>
## 6.内建函数:map/reduce/filter
map/reduce/filter 是 Python 中较为常用的内建高阶函数,它们为函数式编程提供了不少便利。
<a name="TjGR1"></a>
### map
map 函数的使用形式如下:<br />map(function, sequence)<br />**解释**:对 sequence 中的 item 依次执行 function(item),并将结果组成一个 List 返回,也就是:<br />[function(item1), function(item2), function(item3), ...]<br />看一些简单的例子。
```python
>>> def square(x):
return x * x
>>> map(square, [1, 2, 3, 4]) [1, 4, 9, 16]
>>> map(lambda x: x * x, [1, 2, 3, 4]) # 使用 lambda [1, 4, 9, 16]
>>> map(str, [1, 2, 3, 4]) ['1', '2', '3', '4']
>>> map(int, ['1', '2', '3', '4']) [1, 2, 3, 4]
再看一个例子:
def double(x): return 2 x def triple(x): return 3 x def square(x): return x * x funcs = [double, triple, square] # 列表元素是函数对象 # 相当于 [double(4), triple(4), square(4)] value = list(map(lambda f: f(4), funcs)) print value # output [8, 12, 16]
上面的代码中,我们加了 list 转换,是为了兼容 Python3,在 Python2 中 map 直接返回列表,Python3 中返回迭代器。
reduce
reduce 函数的使用形式如下:
reduce(function, sequence[, initial])
解释:先将 sequence 的前两个 item 传给 function,即 function(item1, item2),函数的返回值和 sequence 的下一个 item 再传给 function,即 function(function(item1, item2), item3),如此迭代,直到 sequence 没有元素,如果有 initial,则作为初始值调用。
也就是说:
reduece(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
看一些例子,就能很快理解了。
>>> reduce(lambda x, y: x * y, [1, 2, 3, 4]) # 相当于 ((1 * 2) * 3) * 4 24
>>> reduce(lambda x, y: x * y, [1, 2, 3, 4], 5) # ((((5 * 1) * 2) * 3)) * 4 120
>>> reduce(lambda x, y: x / y, [2, 3, 4], 72) # (((72 / 2) / 3)) / 4 3
>>> reduce(lambda x, y: x + y, [1, 2, 3, 4], 5) # ((((5 + 1) + 2) + 3)) + 4 15
>>> reduce(lambda x, y: x - y, [8, 5, 1], 20) # ((20 - 8) - 5) - 1 6
>>> f = lambda a, b: a if (a > b) else b # 两两比较,取最大值
>>> reduce(f, [5, 8, 1, 10])
10
filter
filter 函数用于过滤元素,它的使用形式如下:
filter(function, sequnce)
解释:将 function 依次作用于 sequnce 的每个 item,即 function(item),将返回值为 True 的 item 组成一个 List/String/Tuple (取决于 sequnce 的类型,python3 统一返回迭代器) 返回。
看一些例子。
>>> even_num = list(filter(lambda x: x % 2 == 0, [1, 2, 3, 4, 5, 6]))
>>> even_num [2, 4, 6]
>>> odd_num = list(filter(lambda x: x % 2, [1, 2, 3, 4, 5, 6]))
>>> odd_num [1, 3, 5]
>>> filter(lambda x: x < 'g', 'hijack') 'ac' # python2
>>> filter(lambda x: x < 'g', 'hijack') <filter object at 0x1034b4080> # python3
小结
- map/reduce/filter 为函数式编程提供了不少便利,可使代码变得更简洁;
- 注意在 python2 和 python3 中,map/reduce/filter 的返回值类型有所不同,python2 返回的是基本数据类型,而 python3 则返回了迭代器;