文章目录
- 前言
- 多进程与多线程
- 基本概念
- 多进程
- multiprocessing 类对象
- 进程池
- subprocess模块
- 进程间通信
- 多线程
- threading实现线程操作
- 线程共享所有变量
- 线程锁
- 参考资料
前言
又花了点时间学习了一下Python中的多线程与多进程的知识点,梳理一下供复习参考
多进程与多线程
基本概念
进程指的是程序的一次执行,它是系统资源分配的单位,不同进程间的资源互相独立,但是系统开销较大
线程是进程的执行单元,它是CPU调度的基本单位,线程能够共享进程的资源,它的优点是效率高,缺点是会影响所在的进程
多进程
multiprocessing 类对象
Python中的多进程常用multiprocessing库实现,支持跨平台的多进程操作,一个实例如下:
from multiprocessing import Process
import os
import time
def run_proc(name):
print('子进程 %s PID: %s 已经启动...' % (name,os.getpid()))
time.sleep(5)
print('子进程 %s PID: %s 终止...' % (name,os.getpid()))
if __name__ == '__main__':
print('父进程PID: %s' % (os.getpid()))
p=Process(target=run_proc,args=('test',))
print('子进程即将启动...')
p.start() #启动进程,并调用该子进程中的p.run()
p.join() #阻塞当前所在进程,等待所有进程退出 #尝试注释此行观察程序执行变化
print('主进程终止...')
- 一个Processs对象就代表一个进程对象,传入的函数名及参数作为进程对象的参数
- 使用start方法启动进程对象,默认调用子进程的run()方法
- join方法表示等待进程结束,此实例中用p.join()表示主进程阻塞,等待子进程执行推出后再继续执行
进程池
利用进程池运行进程的实例如下:
from multiprocessing import Pool
import os,time,random
def long_time_task(name):
print('子进程 %s 启动, PID: %s' % (name, os.getpid()) )
stime=time.time()
# time.sleep(random.random()*3)
time.sleep(1)
etime=time.time()
print('子进程 %s 运行结束,耗时: %f' % (name,(etime-stime)))
if __name__ == '__main__':
print('主进程启动,PID:',os.getpid())
stime=time.time()
p=Pool(2) #Pool()中的参数表示最多能够同时运行几个进程,其余进程需要等到已运行进程结束后才能运行
for i in range(6):
p.apply_async(long_time_task,args=(i,))
print('等待所有子进程运行结束...')
p.close()
p.join()
etime=time.time()
print('所有子进程运行结束,共耗时:',(etime-stime))
执行结果:
解释:
- 每次同时运行两个进程,每个进程执行时间约1秒,共有6个进程,因此执行时间共为3秒
- 如果注释掉 join()的话主进程会直接结束,看不到子进程的输出
subprocess模块
subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。
其中的subprocess.call()则可以调用windows系统cmd命令行执行额外的命令。
import subprocess
print('利用subprocess查询DNS...')
r=subprocess.call(['nslookup','baidu.com'])
print('返回状态码',r)
执行结果
解释:利用subprocess.call()类似于我们开启了一个新的命令窗口(新的进程),输入call()方法的参数,同时将命令执行结果的输出返回到当前进程的输出
进程间通信
multiprocessing模块提供了队列、管道等方式帮助进程之间交换数据
以下例子创建了两个进程,read进程向队列中读取数据,write进程向队列中写入数据
from multiprocessing import Process,Queue
import os,time,random
def write(q):
print('write进程启动,PID:',os.getpid())
for value in ['A','B','C','D']:
print('将',value,'放入队列')
q.put(value)
time.sleep(1)
def read(q):
print('read进程启动,PID:',os.getpid())
while True:
value=q.get()
print('从队列中取出',value)
pass
执行结果:
多线程
- Python支持真正的多线程
- 通常用_thread和threading两个模块实现Python多线程,后者更为常用
- 线程执行的目标是函数,可以为线程命名
threading实现线程操作
import time,threading
def lp():
print('线程',threading.current_thread().name,'正在运行')
for i in range(3):
print('线程进入第',i+1,'次循环')
time.sleep(1)
print('线程',threading.current_thread().name,'终止')
print('线程',threading.current_thread().name,'正在运行')
t=threading.Thread(target=lp,name='子线程')
t.start()
t.join()
print('线程',threading.current_thread().name,'终止')
执行结果
线程共享所有变量
以下是一个简单的例子,利用add和sub线程对共享变量进行修改
import time,threading
share=1000
def add():
global share
share+=5
print('线程',threading.current_thread().name,'正在运行,变量share自增, share:',share)
time.sleep(1)
def sub():
global share
share-=2
print('线程',threading.current_thread().name,'正在运行,变量share自减, share:',share)
time.sleep(1)
t1=threading.Thread(target=add,name='add')
t2=threading.Thread(target=sub,name='sub')
t1.start()
t2.start()
t1.join()
t2.join()
print('share:',share)
执行结果:
线程锁
让我们尝试修改一下上面的例子,add和sub线程随机修改三次共享变量share,没有线程锁时将出现混乱,我们无法预测哪个线程先对share变量进行修改,程序每次运行的结果可能会有不一样:
import time,threading,random
share=1000
lock=threading.Lock()
def add():
global share
#随机自增三次
for i in range(3):
share+=random.randint(1,10)
print('线程',threading.current_thread().name,'正在运行,变量share随机自增, share:',share)
time.sleep(random.random())
def sub():
global share
#随机自减三次
for i in range(3):
share-=random.randint(1,10)
print('线程',threading.current_thread().name,'正在运行,变量share随机自减, share:',share)
time.sleep(random.random())
t1=threading.Thread(target=add,name='add')
t2=threading.Thread(target=sub,name='sub')
t1.start()
t2.start()
t1.join()
t2.join()
print('share:',share)
运行结果:
加入线程锁之后,就可以等到某个线程执行结束后再执行另一个线程,不会出现交替执行的情况
import time,threading,random
share=1000
lock=threading.Lock()
def add():
global share
#随机自增三次
try:
lock.acquire()
for i in range(3):
share+=random.randint(1,10)
print('线程',threading.current_thread().name,'正在运行,变量share随机自增, share:',share)
time.sleep(random.random())
finally:
lock.release()
def sub():
global share
#随机自减三次
try:
lock.acquire()
for i in range(3):
share-=random.randint(1,10)
print('线程',threading.current_thread().name,'正在运行,变量share随机自增, share:',share)
time.sleep(random.random())
finally:
lock.release()
t1=threading.Thread(target=add,name='add')
t2=threading.Thread(target=sub,name='sub')
t1.start()
t2.start()
t1.join()
t2.join()
print('share:',share)
执行结果:
参考资料
Python正则表达式
Python多进程与多线程
subprocess.call()