进程、线程与协程

进程

进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例

程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配 CPU 时间,然后程序开始真正运行

Linux 系统函数 fork() 可以在父进程中创建一个子进程:

import os

print('当前进程:%s 启动中 ....' % os.getpid())
pid = os.fork()
if pid == 0:
    print('子进程:%s,父进程是:%s' % (os.getpid(), os.getppid()))
else:
    print('进程:%s 创建了子进程:%s' % (os.getpid(),pid ))

Multiprocess 是 Python 中的多进程管理包,要用来帮助处理进程的创建以及它们之间的通信和相互协调。它主要解决了两个问题:

  • 提供高层次的 API ,使得使用者忽略底层平台之间的差异
  • 提供对复杂对象的共享支持,支持本地和远程并发
  • 进程间的内存共享细节可参阅 multiprocessing.shared_memory类

线程

线程是程序执行时的最小单位,它是进程的一个执行流,是 CPU 调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量

线程由 CPU 独立调度执行,在多 CPU 环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理

全局解释器 GIL 的存在使 Python 多线程无法充分利用多核优势来提高性能

CPython 下,因为 ,一个时刻只有一个线程可以执行 Python 代码(尽管如此,某些性能导向的库可能会克服这个限制)。如果你想让你的应用更好的利用多核计算机的计算性能,推荐你使用 <code>multiprocessing</code> 或者 <code>concurrent. Futures. ProcessPoolExecutor</code> 。但是如果你想同时运行多个 I/O 绑定任务,线程仍然是一个合适的模型。

具体可参考 threading文档--基于线程的并行

线程 VS 进程

  • 进程是资源分配的最小单位,线程是程序执行的最小单位
  • 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵
  • 而线程是共享进程中的数据的,使用相同的地址空间,因此 CPU 切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多
  • 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点
  • 多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间

其他补充:

协程

协程(Coroutine),又称微线程,纤程

  • 相比于线程,协程具有执行效率高且不用加锁的优点
  • 协程适合 I/O 密集型任务,但由一个线程执行,无法利用 CPU 的多核能力
  • 通过 多进程+协程,既充分利用 CPU 的多核能力,又发挥了协程的高效率

Gevent 是一个第三方库,可以轻松通过 gevent 实现并发同步或异步编程,在 gevent 中用到的主要模式是 Greenlet, 它是以 C 扩展模块形式接入 Python 的轻量级协程。

Python 示例:通过协程实现一个生产者-消费者模型

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None)
    n = 0
    while n < 3:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)

执行结果:

[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK

参考

廖雪峰-python教程-异步IO-协程
一道面试题:说说进程和线程的区别

往年同期文章