Python:进程与线程

Python:进程与线程

单核 CPU 是如何执行任务的呢?操作系统轮流让各个任务交替执行,任务 1 执行 0.01s,切换到任务 2,任务 2 执行 0.01s,再切换到任务 3,这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于 CPU 的执行速度实在太快了,我们感觉就像所有任务在同时执行一样。

真正的并行执行多任务只能在多核 CPU上实现,但是,由于任务数量远远多于 CPU 和核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。

对于操作系统来说,一个任务就是一个进程 Process,比如打开一个浏览器就是启动一个浏览器进程。在一个进程内部,要同时干多件事情,就需要同时运行多个子任务,我们把进程内的这些子任务成为线程 Thread。

由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像 Word 这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多线程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核 CPU 才可能实现。

多任务的实现有 3 种方式:

  • 多进程模式
  • 多线程模式
  • 多进程 + 多线程模式

多进程

multiprocessing 模块提供了一个 Process 类来代表一个进程对象。

from multiprocessing import Process
import os


def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))


if __name__ == '__main__':
    print('Parent process %s.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('Child process will start.')
    p.start()
    p.join()
    print('Child process end.')

多线程

启动一个线程就是把一个函数传入并创建 Thread 实例,然后调用 start( ) 开始执行。

import time, threading


def loop():
    print('thread %s is running...' % threading.current_thread().name)
    n = 0
    while n < 5:
        n = n + 1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s ended.' % threading.current_thread().name)


if __name__ == "__main__":
    print('thread %s is running...' % threading.current_thread().name)
    t = threading.Thread(target=loop, name='LoopThread')
    t.start()
    t.join()
    print('thread %s ended.' % threading.current_thread().name)

线程锁

balance = 0
lock = threading.Lock()

def run_thread(n):
    for i in range(100000):
        # 先要获取锁 :
        lock.acquire()
        try:
            # 放心地改吧 :
            change_it(n)
        finally:
            # 改完了一定要释放锁 :
            lock.release()

Python 的线程虽然是真正的线程,但解释器执行代码时,有一个 GIL 锁:Global Interpreter Lock,任何 Python 线程执行前,必须先获得 GIL 锁,然后,每执行 100 条字节码,解释器就自动释放 GIL 锁,让别的线程有机会执行。这个全局 GIL 全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在 Python 中只能交替执行,即使 100 个线程跑在 100 核 CPU 上,也只能用到 1 个核。

非原创,原文来源廖雪峰 Python 教程。