Python线程、进程与协程的区别
1. 线程
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是比进程更小的能独立运行的基本单位。在Python中,线程是通过threading模块实现的。
线程的创建
Python中的线程创建过程非常简单,只需要调用threading模块的Thread方法,并将需要执行的函数作为参数传入即可。下面是一个例子:
import threading
def print_hello():
for i in range(5):
print("Hello")
def print_world():
for i in range(5):
print("World")
thread1 = threading.Thread(target=print_hello)
thread2 = threading.Thread(target=print_world)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
这段代码创建了两个线程,分别执行print_hello和print_world函数,输出结果是交叉的。
线程的同步
由于Python的全局解释器锁(GIL),所以在多线程环境下,同一时间只能有一个线程在执行Python代码。但是线程之间需要共享变量,如果多个线程同时访问同一个变量,就会引发线程安全问题。解决这个问题的方法就是使用线程同步机制,最常见的就是使用Lock。
下面是一个例子:
import threading
num = 0
lock = threading.Lock()
def add_num():
global num
for i in range(1000000):
lock.acquire()
num += 1
lock.release()
thread1 = threading.Thread(target=add_num)
thread2 = threading.Thread(target=add_num)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(num)
这段代码创建了两个线程,分别执行add_num函数,这个函数的目的就是让num加1。由于num是共享变量,需要使用Lock来同步线程,最后输出的结果应该是2000000。
2. 进程
进程是资源分配的最小单位,是运行中的程序的一个实例。进程有自己独立的内存空间,每个进程之间是相互独立的。在Python中,进程可以通过multiprocessing模块来创建。
进程的创建
与线程类似,Python中的进程也可以通过传入准备执行的函数来创建。下面是一个简单的例子:
import multiprocessing
def print_hello():
for i in range(5):
print("Hello")
def print_world():
for i in range(5):
print("World")
process1 = multiprocessing.Process(target=print_hello)
process2 = multiprocessing.Process(target=print_world)
process1.start()
process2.start()
process1.join()
process2.join()
这段代码创建了两个进程,分别执行print_hello和print_world函数,输出结果是交替输出。
进程池
由于每个进程都需要占用一定的系统资源,如果需要同时运行大量的进程,可能会导致系统资源不足。为了解决这个问题,Python提供了进程池来管理进程的数量。
下面是一个例子:
import multiprocessing
def print_hello():
for i in range(5):
print("Hello")
def print_world():
for i in range(5):
print("World")
if __name__ == '__main__':
process_pool = multiprocessing.Pool(processes=2)
process_pool.apply_async(print_hello)
process_pool.apply_async(print_world)
process_pool.close()
process_pool.join()
这段代码创建了一个进程池,最多可以执行两个进程,然后使用apply_async方法异步执行print_hello和print_world函数。
3. 协程
协程是一种用户态的轻量级线程,可以在一个线程中执行多个任务,但是不能利用多核资源。Python中的协程可以使用asyncio模块来编写。
协程的创建
协程的创建过程与线程和进程不同,需要使用async和await关键字来定义协程函数。下面是一个简单的例子:
import asyncio
async def print_hello():
for i in range(5):
print("Hello")
await asyncio.sleep(1)
async def print_world():
for i in range(5):
print("World")
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
tasks = [print_hello(), print_world()]
loop.run_until_complete(asyncio.gather(*tasks))
loop.close()
这段代码定义了两个协程函数print_hello和print_world,分别输出Hello和World,每个输出之间间隔1秒。
协程的异步调用
协程最大的优势就是可以实现异步调用,对于IO密集型的任务效果非常好。下面是一个简单的例子:
import asyncio
import aiohttp
async def download(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
content = await response.text()
return content
loop = asyncio.get_event_loop()
result = loop.run_until_complete(download("http://www.baidu.com"))
print(len(result))
loop.close()
这段代码使用aiohttp库下载了百度首页,并且使用异步调用提高了并发效率。
总结
Python中的线程、进程和协程都有自己的优点和限制,需要根据具体的应用场景来选择。线程因为受到GIL的限制,所以适合IO密集型的任务,进程可以利用多核资源,适合CPU密集型的任务,而协程可以实现高效的异步调用,适合IO密集型的任务。