python入门:多任务

42 阅读5分钟

多任务

并行多任务:多个任务同时执行,任务数小于CPU核数时可以实现
并发多任务:多个任务交替执行,任务数高于CPU核数,通过任务调用算法看似同时进行
进程:是操作系统进行资源分配的基本单位,一个正在进行的程序或软件就是一个进程,占用CPU一核
线程:是程序执行的基本单位;一个进程默认有一个主线程,可以创造多个子线程
多线程、多进程运行即可完成多任务

多线程

使用threading模块里的Thread类创造实例,用start()方法启动子线程
线程类Thread参数:group(线程组)target(执行目标的函数名)args(以元组方式给执行任务传参)kwargs(以字典方式传参)name(线程名)

创建线程

1.import threading 导入threading模块
2. t1=threading.Thread(target=函数名 ,args=(参数 ,)) 创造子线程Thread()类
3.t1.setDaemon(True) 守护线程(可选)主线程执行完时子线程也跟着结束
4.t1.start() 启动子线程
5.t1.join() 阻塞主线程(可选)主线程等子线程执行完再执行

run方法

执行start()时自动调用,创建Thread的子类重新定义run函数

线程同步

多线程的执行是异步无序的,都对共享数据(如全局变量)有操作时,同时进行会出现资源竞争,导致多个线程同时操作共享数据
线程同步:线程之间相互协同,一个线程需要停下接收另一个线程的某个结果后才能继续执行,避免资源竞争 方法一:线程等待join()
方法二:互斥锁,对共享数据进行锁定,保证同一时间只有一个线程操作
1.导入threading模块
2.lock=Lock() 创建互斥锁实例
3.lock.acquire() 上锁,加在函数中,在释放之前其余上锁步骤会堵塞
4.lock.release() 解锁,加在函数中,其他线程的上锁步骤在互斥锁释放后开始执行

多进程

使用multiprocessing模块的Process类

创建进程

1.import multiprocessing 导入模块
2.p1=Process() 创建子进程
3.p1.start() 启动子进程
4.p1.join() 阻塞主进程,括号内可填入阻塞时间上限
5.p1.terminate 终止子进程

p1.is_alive() 判断子进程是否还未结束,返回布尔型
多进程间不共享全局变量,适用于计算/IO密集的任务,但同时消耗也比多线程大

进程通信

队列:先进先出(FIFO) 入队:将一个数据放在队列尾部 出队:将队列头部的一个数据取出 maxsize:队列中能存放的数据上限 达到上限就会堵塞,直到队列中的数据被消费;不设置则无上限

进程间为异步通信,使用multiprocessing模块的Queue类进行数据传递,Queue本身就是一个消息列队程序 q=Queue() 创建队列实例,括号内可填入上限
q.empty()判断队列是否为空,q.full()判断队列是否充满,都返回布尔型
q.qsize() 查看队列数据数
q.put(数据) 放入数据,q.put(数据 ,True ,阻塞时长) 决定队列满溢时先阻塞一定时长,如果还没有空间再报错
a=q.get() 取出数据

线程间通信可用queue模块的Queue类进行

进程池

先启动多个进程,再等待主进程进行任务分配,执行后的进程不会立即关闭而是返回池里等待重复使用 使用multiprocessing模块中的Pool类 p=Pool() 创造进程池,括号内可填入上限
p.apply_asymc(函数名 ,args ,kwargs) 以非阻塞的方式异步调用函数进程;p.apply()以阻塞的方式同步调用函数进程
p.close() 关闭进程池,不接收新任务,只执行已分配任务
p.join() 阻塞进程池,等待所有进程结束,放在p.close()
enumerate() 立即终止任务

进程池通信:使用multiprocessing.Manager()中的Queue()
创建队列实例q=Manager().Queue()

提交任务的两种方式
同步调用:提交完任务后进行阻塞,等到任务结束接收到任务的返回值后,才继续执行
异步调用:提交完任务后不进行阻塞,直接继续执行

协程

单线程下的并发多任务,通过代码规定执行顺序
不需要通过cpu来调度,是一种用户轻量级线程
协程能保留上一次调用时的状态
应用于IO特别多的场景

创建协程

1.yield方法:函数中加 yield 数据,用next(函数())启动,执行到此时暂停执行并返回数据,等到下一次启动时从暂停处继续执行
2.greenlet方法:from greenlet import greenlet 从greenlet模块中导入greenlet类
gr1=greenlet(函数名) 创建greenlet实例
x=gr1.switch(参数) 使用switch方法启动协程,第一次启动协程时括号内参数传给对应函数,之后从暂停处继续时作为暂停处的返回值;当协程中执行到其他协程的switch(gr2.switch())时,暂停该协程转去执行对应协程,直到在其他协程中执行到该协程的switch(gr1.switch())时,切换回来从暂停处继续执行,直到协程执行完成后释放,需要让协程执行完毕

import greenlet
def test1(x, y):
    z=gr2.switch(x+y)
    print(z) #输出123abc

def test2(u):
    print(u) #输出123abc
    gr1.switch(u)

gr1 = greenlet.greenlet(test1)
gr2 = greenlet.greenlet(test2)
print(gr1.switch("123" ,"abc"))  #输出None

greenlet.dead 协程是否终止,返回布尔型
3.gevent方法:遇到IO时自动切换模块
import gevent
创建协程实例并启动 g1=gevent.spawn(函数 ,参数)
g1.join() 阻塞协程
gevent.joinall(协程列表) 阻塞列表内所有协程,等待所有协程执行结束
当执行到耗时操作时自动跳转执行其他协程,等耗时操作结束时再接回继续执行