进程(Process) 线程(thread)协程(Coroutine)
进程(Process) 线程(thread)协程(Coroutine)
进程(Process):
进程是操作系统进行资源分配和调度的基本单位,是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。进程是应用程序的一个实例,拥有它自己的内存空间和系统资源。每个进程都运行在它自己的地址空间内。
import multiprocessing
import os
def worker1():
# 打印当前进程的 id
print('Worker 1, PID = %d' % os.getpid())
def worker2():
# 打印当前进程的 id
print('Worker 2, PID = %d' % os.getpid())
if __name__ == '__main__':
# 创建两个进程,目标函数分别是 worker1 和 worker2
p1 = multiprocessing.Process(target=worker1)
p2 = multiprocessing.Process(target=worker2)
# 启动两个进程
p1.start()
p2.start()
# 等待两个进程执行完毕
p1.join()
p2.join()
print('Both workers completed.')
线程(Thread):
线程是进程的一个执行实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程可以创建多个线程,所有线程共享进程的资源,如内存空间等。线程之间的切换比进程之间的切换要快,因为线程是在同一进程内切换,不需要切换内存空间和共享资源。
import threading
import time
def thread1():
print('Thread 1 starting.')
time.sleep(3)
print('Thread 1 finishing.')
def thread2():
print('Thread 2 starting.')
time.sleep(3)
print('Thread 2 finishing.')
if __name__ == '__main__':
# 创建两个线程,目标函数分别是 thread1 和 thread2
t1 = threading.Thread(target=thread1)
t2 = threading.Thread(target=thread2)
# 启动两个线程
t1.start()
t2.start()
# 等待两个线程执行完毕
t1.join()
t2.join()
print('Both threads completed.')
注:由于 Python 的 Global Interpreter Lock(GIL)的存在,Python 的多线程并不适合用于 CPU 密集型任务,因为 GIL 会导致在任何时刻只有一个线程在执行。但是,对于 I/O 密集型任务,如文件操作、网络请求等,多线程仍然是一个很好的选择,因为在等待 I/O 操作完成时,其他线程可以继续执行。
协程(Coroutine):
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程有点像线程,但协程的切换不涉及系统调用,而是程序通过 yield 关键字将 CPU 控制权交给其他协程,因此效率比线程高很多。协程的主要优点是极高的执行效率和极低的上下文切换成本。同时,由于协程是在用户态下切换,所以可以跨越多个线程,利用多核处理器的优势。
import asyncio
async def coroutine1():
print('Coroutine 1 starting.')
await asyncio.sleep(3)
print('Coroutine 1 finishing.')
async def coroutine2():
print('Coroutine 2 starting.')
await asyncio.sleep(3)
print('Coroutine 2 finishing.')
if __name__ == '__main__':
# 创建一个事件循环
loop = asyncio.get_event_loop()
# 创建两个协程,目标函数分别是 coroutine1 和 coroutine2
tasks = [coroutine1(), coroutine2()]
# 使用事件循环来执行协程
loop.run_until_complete(asyncio.gather(*tasks))
print('Both coroutines completed.')
注:协程的一个重要特性是能够在函数内部,利用 await 关键字挂起函数的执行,等待异步操作完成。这使得协程非常适合用于 I/O 密集型任务,如文件操作、网络请求等,因为在等待 I/O 操作完成时,其他协程可以继续执行,从而提高程序的整体性能。
请注意,协程并不是并行执行的,它们是在一个线程内部并发执行的。具体的执行顺序由事件循环控制。
总结一下,进程、线程和协程都是程序执行流的不同抽象层次。进程拥有完全独立的资源,线程是进程内的执行实体,共享进程资源,而协程则是线程内的执行实体,可由程序自行调度,不需要操作系统的干预。