1. 进程的定义

进程是系统进行资源分配和调度的一个独立单位。
进程拥有自己独立的内存空间,所以进程间数据不共享,创建和销毁进程的开销比较大。

  1. import multiprocessing
  2. import time
  3. def sing():
  4. for i in range(89):
  5. print('----正在唱歌-----')
  6. time.sleep(1)
  7. def dance():
  8. for i in range(3):
  9. print('----正在跳舞-----')
  10. time.sleep(89)
  11. if __name__ == '__main__':
  12. #创建两个进程
  13. p1=multiprocessing.Process(target=sing)
  14. p2=multiprocessing.Process(target=dance)
  15. # 开始执行进程
  16. p1.start()
  17. p2.start()

进程之间通讯

1).queue队列
2).进程池
队列是一种先进先出的存储数据结构,就比如排队上厕所一个道理。两个进程通讯,就是一个子进程往queue中写内容,另一个进程从queue中取出数据。就实现了进程间的通讯了。

创建 queue队列对象

  1. 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())

  1. <a name="T4wtc"></a>
  2. ## 2. 线程的定义
  3. 线程是进程的一个实体,是CPU调度和分派的基本单位。<br />线程必须依赖于进程存在。一个进程至少拥有一个线程,叫主线程。而多个线程共享内存,从而极大地提高了运行效率。
  4. <a name="XUmih"></a>
  5. ### 如何避免多线程竞争资源
  6. - **加锁**
  7. - **使用队列(queue)**
  8. <a name="7S7V4"></a>
  9. ## 3.协程的定义
  10. 协程则是程序级别的由程序根据需要自己调度。<br />在一个线程中会有很多函数,我们把这些函数称为子程序,在子程序执行过程中可以中断去执行别的子程序,而别的子程序也可以中断回来继续执行之前的子程序,这个过程就称为协程。<br />协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。
  11. <a name="82PmJ"></a>
  12. ### 协程的优点:
  13. - 无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力)
  14. - 无需原子操作锁定及同步的开销
  15. - 方便切换控制流,简化编程模型
  16. - 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
  17. <a name="8ny7V"></a>
  18. ### 协程的缺点:
  19. - 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  20. - 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
  21. <a name="A4uFu"></a>
  22. ## 4.进程、线程、协程之间的区别
  23. 一个程序至少有一个进程,一个进程至少有一个线程<br />线程是划分尺度较小的进程(资源比进程占用的少),使得多线程程序的并发性高。<br />进程在执行的过程中拥有独立的内存单元,而多个线程共享这块内存空间,从而极大的提高了程序的运行效率。<br />线程不能独立执行,必须依存在进程中。
  24. <a name="dMaWN"></a>
  25. ### 定义的不同
  26. - 进程是系统进行资源分配最小单元,线程是调度执行的最小单位。
  27. - 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序执行的需要的cpu资源),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源(主要是内存资源).
  28. <a name="nWlHi"></a>
  29. ### 区别
  30. - 一个程序至少有一个进程,一个进程至少有一个线程.
  31. - 线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
  32. - 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
  33. - 线程不能够独立执行,必须依存在进程中
  34. <a name="78102351"></a>
  35. ### 优缺点
  36. 线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
  37. <a name="jAc5u"></a>
  38. ## 5.GIL 锁
  39. 讲到 Python 中的多线程,就不得不面对 GIL 锁,GIL 锁的存在导致 Python 不能有效地使用多线程实现多核任务,因为在同一时间,只能有一个线程在运行。<br />GIL 全称是 Global Interpreter Lock,译为**全局解释锁**。早期的 Python 为了支持多线程,引入了 GIL 锁,用于解决多线程之间数据共享和同步的问题。但这种实现方式后来被发现是非常低效的,当大家试图去除 GIL 的时候,却发现大量库代码已重度依赖 GIL,由于各种各样的历史原因,GIL 锁就一直保留到现在。
  40. <a name="crM4a"></a>
  41. ## 6.内建函数:map/reduce/filter
  42. map/reduce/filter 是 Python 中较为常用的内建高阶函数,它们为函数式编程提供了不少便利。
  43. <a name="TjGR1"></a>
  44. ### map
  45. map 函数的使用形式如下:<br />map(function, sequence)<br />**解释**:对 sequence 中的 item 依次执行 function(item),并将结果组成一个 List 返回,也就是:<br />[function(item1), function(item2), function(item3), ...]<br />看一些简单的例子。
  46. ```python
  47. >>> def square(x):
  48. return x * x
  49. >>> map(square, [1, 2, 3, 4]) [1, 4, 9, 16]
  50. >>> map(lambda x: x * x, [1, 2, 3, 4]) # 使用 lambda [1, 4, 9, 16]
  51. >>> map(str, [1, 2, 3, 4]) ['1', '2', '3', '4']
  52. >>> 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 则返回了迭代器;