今天学习了 Python 中进程和线程的核心用法,涵盖进程创建、进程间通信、线程使用、线程数据共享等关键知识点.

一、进程相关

1. 自定义进程类(继承 Process)

        通过继承multiprocessing.Process类自定义进程,需重写run()方法定义进程执行逻辑,初始化时要调用父类的__init__方法,支持传入自定义参数和 Process 类的原生参数.        

class Study(Process):
    def __init__(self,a,b,**kwargs):
        super().__init__(**kwargs)  # 继承Process的参数
        self.a = a
        self.b = b
    def run(self):  # 进程执行的核心逻辑
        print(f'{self.a,self.b} - 进程ID:{os.getpid()}, 父进程ID:{os.getppid()}')

        创建并启动进程:study = Study('hello','world',name='进程1') → study.start()。

2. 进程池(ProcessPoolExecutor)

        使用concurrent.futures.ProcessPoolExecutor创建进程池,控制并行,避免资源耗尽,通过submit()提交任务,result()获取任务返回值,shutdown()等待所有任务完成。

executor = ProcessPoolExecutor(3)  # 最多3个进程
f1 = executor.submit(study, 1)  # 提交任务
print(f1.result())  # 获取返回值
executor.shutdown(wait=True)  # 等待所有任务执行完毕

3. 进程间通信(IPC)

        进程间相互隔离,需通过专用机制通信,核心有两种方式:

        Queue 队列:先进先出(FIFO)结构

        数据通过 “序列化→拷贝→共享内存→反序列化” 传递(非共享,是拷贝)。

        支持put()(入队,满时阻塞)、get()(出队,空时阻塞),还有get_nowait()(非阻塞,空则抛异常)、empty()/full()/qsize()等方法。

q = Queue(2)  # 容量为2的队列
p1 = Process(target=test1, args=(q,))  # 子进程1往队列放数据
p2 = Process(target=test2, args=(q,))  # 子进程2从队列取数据

        Pipe 管道:类似 “水管”,可设置单向(duplex=False)/ 双向,通过send()发送数据、recv()接收数据。

con1, con2 = Pipe(duplex=False)  # con1接收,con2发送
p1 = Process(target=test, args=(con1,))
p2 = Process(target=test2, args=(con2,))

二、线程相关

1. 线程创建与使用

        通过threading.Thread创建线程,用法与 Process 类似,需指定target(执行函数)、args(参数)等,核心方法:
        start():启动线程(交给操作系统调度);
        join():等待线程执行完毕;
        daemon=True:设置为守护线程(主进程 / 主线程结束,守护线程立即终止)。

lock = Lock()
p = Thread(target=study, args=(lock,), name='study')
p.daemon = True  # 守护线程
p.start()
p.join()  # 等待线程执行完

2. 线程数据共享与锁机制

        线程共享进程的内存空间,全局变量可直接共享,但多线程修改共享数据会出现 “竞态条件”,需通过threading.Lock加锁/join()保证原子性:
        acquire():获取锁(加锁);
        release():释放锁(解锁);
        也可使用with lock自动加锁 / 释放锁,更简洁。

num = 0  # 共享全局变量
def num1(lock):
    global num
    lock.acquire()
    for i in range(10000000):
        num += 1  # 加锁避免多线程同时修改
    lock.release()

3. 进程与线程的基础标识

        进程 ID:os.getpid()(当前进程)、os.getppid()(父进程);
        线程 ID:threading.get_native_id()(当前线程编号)。

三、核心区别(进程 vs 线程)

        进程是资源分配的最小单位,线程是 CPU 调度的最小单位
        进程间相互隔离,需 IPC 通信;线程共享进程资源,需锁保证数据安全;
        进程创建 / 销毁开销大,线程开销小;
        多进程可利用多核 CPU,多线程受 GIL 限制(Python 中同一时刻仅一个线程执行)。

四、注意事项

        进程 / 线程创建时,start()才是真正向操作系统申请资源,仅创建对象不会启动;
        队列put()/get()默认阻塞,可通过timeout/block=False设置非阻塞;
        锁的使用要避免死锁,确保acquire()后必有release(),推荐with lock语法;
        守护线程 / 进程需在start()前设置,主进程结束时,未设置守护的子进程会继续执行,守护的则终止。

更多推荐