多线程 进程 协程
01 threading实现多线程
导入threading模块
import threading-
创建对象
def sing(): for i in range(5): print("------Singing-----") time.sleep(1) ts = threading.Thread(target=sing)
注意 target参数只写函数名,不能加括号,此时只创建了对象,没有创建线程
-
控制子线程
ts.start() # 启动子线程 ts.join([time]) # 等待子线程运行完成 ts.isAlive() # 返回子线程是否是存活的 ts.getName() # 返回子线程名 ts.setName() # 设置子线程名
调用start之后才创建了子线程,子线程从start开始执行,目标函数结束后子线程运行结束
-
运行多个子线程
while True: length=len(threading.enumerate()) # print("\n当前运行的进程数:%d\n"%length) time.sleep(2) if length <= 1: print("\n所有子线程已运行完成!!!\n") break
len(threading.enumerate())表示当前运行的线程数,包括一个主线程
-
通过重载使用多线程
import threading import time class MyThread(threading.Thread): def run(self): for i in range(3): time.sleep(1) print("-----%d-----"%i) self.relax() def relax(self): print('-----relax-----\n') if __name__=='__main__': t=MyThread() t.start()
调用start时会自动调用类中的run,因此在类中必须定义run
-
互斥锁
- 创建锁(默认是不加锁的) mutex=threading.Lock()
- 上锁 mutex.acquire()
- 解锁 mutex.release()
- 判断是否上锁 mutex.locker()
02 multiprocessing实现多进程
进程与线程的区别:
- 进程是资源分配的单位,线程是资源调度的单位
- 进程需要的资源多 线程需要的资源少
- 进程如同一条流水线 线程如同流水线上的工人
导入模块
import multiprocessing-
创建对象
import time import multiprocessing def sing(): for i in range(5): print("------Singing-----") time.sleep(1) def dance(): for i in range(5): print("------Dancing-----") time.sleep(1) def main(): ts=multiprocessing.Process(target=sing) td=multiprocessing.Process(target=dance) ts.start() td.start() if __name__=='__main__': main()
- 调用start后才创建了子进程,子进程从start开始执行,子线程函数结束后子进程运行结束
- 子进程会将主进程的内存复制,复制变量的值。 代码是共享的,不复制 复制的越少越好,能共享就共享
-
queue实现进程间通信
import multiprocessing # 模拟下载数据 def download_data(q): data=[1,2,3,4,5] for temp in data: q.put(temp) print('所有数据已经存入!') # 模拟处理数据 def data_process(q): get_data=list() while (q.empty()==False): data=q.get() get_data.append(data) print(get_data) def main(): #创建一个队列 q=multiprocessing.Queue() p1=multiprocessing.Process(target=download_data,args=(q,)) p2=multiprocessing.Process(target=data_process,args=(q,)) p1.start() p2.start() if __name__=='__main__': main()
1. queue在内存中开辟空间,储存用于通信的数据
queue只能用于同一个电脑的同一个程序
不指定队列大小时,根据内存自动确定大小
创建进程传递参数时,要注意传递的是一个元组,要加逗号
-
进程池
在任务数不确定时,往往使用进程池import multiprocessing import os,time,random def job(msg): t_start=time.time() print('%s开始执行,进程号为:%d'%(msg,os.getpid())) time.sleep(random.random()*3) t_stop=time.time() t_cost=t_stop - t_start print('%s执行执行完毕,耗时%0.2fs' % (msg, t_cost)) def main(): po=multiprocessing.Pool(3) # 设置进程池容量为3 for i in range(10): po.apply_async(job,(i,)) # 两个参数为要执行的函数名和传递参数元组 print('----start----') po.close() # 关闭进程池 po.join() # 等待池中所有进程执行结束 必须在close之后 print('----end----') if __name__=='__main__': main()
- 创建容纳三个进程的进程池去执行九个任务
- 进程池使用queue通信时,要使用manager下的queue
如q=multiprocessing.Manager().Queue()
03 gevent实现协程
-
gevent再遇到延时函数时会自动切换协程,但要注意需要使用gevent中的延时函数,如将time.sleep()换成gevent.sleep()
如果想要使用原来的延时函数,可以添加语句:gevent.monkey.patch_all()
-
启动多个协程的方法
gevent.joinall( [ gevent.spawn(f1,5), gevent.spawn(f2,5), gevent.spawn(f3,5) # 设置目标函数并传递参数 ] )
协程传递参数使用的不是元组
-
代码示例
from gevent import monkey gevent.monkey.patch_all() def f1(n): for i in range(n): print('f1:',i) time.sleep(1) def f2(n): for i in range(n): print('f2:',i) time.sleep(1) def f3(n): for i in range(n): print('f3:',i) time.sleep(1) gevent.joinall( [ gevent.spawn(f1,5), gevent.spawn(f2,5), gevent.spawn(f3,5) ] )