本文共 2840 字,大约阅读时间需要 9 分钟。
线程是程序执行的最小单元,进程是资源分配的最小单位。每个进程可以包含多个线程,而每个线程在执行时会独占CPU。与进程不同,线程共享进程的地址空间和资源,这使得线程切换更加高效。
在Python中,Global Interpreter Lock(GIL)用于限制同一进程中同时执行的线程数量。GIL在执行100条指令后切换线程,确保线程安全。默认情况下,GIL锁会在每个进程中限制同时运行的线程数量。
线程的主要作用是利用多核CPU的优势实现并行执行。通过创建多个线程,可以同时处理多个任务,提高系统性能。
线程切换成本低,但线程间通信需要同步机制。进程间通信则需要通过 IPC(进程间通信)实现。
协程是一种微线程,由程序员手动控制线程切换。与线程不同,协程是在代码块之间进行切换,而不是逐行执行。
IO多路复用用于检测多个socket是否有数据到来或连接请求。它支持三种模式:select、poll和epoll,适用于不同的IO调度需求。
异步编程允许程序在执行IO操作时立即返回,并自动执行后续操作。与同步编程不同,异步操作不会阻塞当前线程。
通过设置socket的非阻塞属性(setblocking(False)),可以避免等待IO操作。但需处理可能的BlockingIOError异常。
协程框架(如gevent)通过自动切换线程实现IO非阻塞,提升了并发性能。
事件驱动框架(如Twisted)通过事件循环实现异步编程,执行完成后自动调用回调函数。
单线程通过IO多路复用和非阻塞socket实现并发,适用于资源受限的环境。
import socketimport select# 创建三个socket对象并设置为非阻塞client_baidu = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client_baidu.setblocking(False)client_sogou = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client_sogou.setblocking(False)client_github = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client_github.setblocking(False)# 初始化事件循环socket_list = [client_baidu, client_sogou, client_github]conn_list = [client_baidu, client_sogou, client_github]while True: rlist, wlist, elist = select.select(socket_list, conn_list, [], 0.5) for sk in wlist: if sk == client_baidu: sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n') elif sk == client_sogou: sk.sendall(b'GET /web?query=fdf HTTP/1.0\r\nhost:www.sogou.com\r\n\r\n') else: sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.oldboyedu.com\r\n\r\n') conn_list.remove(sk) for sk in rlist: chunks = [] while True: try: chunk = sk.recv(8096) if not chunk: break chunks.append(chunk) except BlockingIOError: break body = b''.join(chunks) print('Download complete:', body.decode('utf-8')) sk.close() socket_list.remove(sk) if not socket_list: break 选择合适的并发策略(多进程、多线程、协程、单线程)取决于任务特点和资源约束。理解GIL锁的机制和IO多路复用的应用,是实现高效并发的关键。
转载地址:http://scgyz.baihongyu.com/