进程
- 进程就是程序执行的载体;
- 打开的每个软件、游戏,执行的每一个python脚本都是一个进程;
多进程
- 可以同时启动多个进程,这些进程都是在执行程序,但是他们互不干扰,各自执行自己的业务逻辑
- 并行处理:多个cpu内核同时执行,多进程在不同的内核(跑道)中执行(同一时间处理多个事情)
- 进程负责吸收足够程序跑起来的资源(cup,内存),并交给线程,线程则是真正执行业务逻辑的角色;
- 进程提供线程执行程序的前置要求,线程在重组的资源配备下,去执行程序
线程
- 先有进程再有线程
- 主线程、子线程
多线程
- 并发:单个cpu内核中多个线程同时工作。把一个核心中多个时间片上同时处理线程的行为称为并发。
多进程的问题
- 通过进程模块执行的函数无法获取返回值
- 多个进程同时修改文件可能会出现错误
- 进程数量太多可能会造成资源不足,甚至死机等情况
进程池
- 包含一定数量进程的池子该进程池中的进程伴随进程池一起被创建。
- 可以被重复使用。
- 进程池关闭时,池中的进程也会被关闭
- 当有任务执行时,会首先判断池子中有没有空闲的进程,如果有空闲的进程,则该任务交给空闲的进程,如果没有则需要等待,直到有执行完成的空闲的进程
进程池的创建–multiprocessing
- 创建进程池:pool = multiprocessing.Pool(Processcount)
- 任务加入进程池(异步):pool.apply_async(func, args)
- 关闭进程池:.close
- 等待进程池任务结束:.join
进程锁
- 看到进程就会给进程上一把锁,进门上锁,开门解锁
from multiprocessing import Manager
manage = Manager()
lock = manager.Lock()
- 上锁:acquire
- 开锁(解锁):release
进程的通信
- 什么是进程的通信:当两个进程建立通话之后,两个进程之间就会建立一条隐形的队列。A进程要发信息到B进程就需要队列的帮助,队列支持发送消息和接收消息。
队列的创建:
- send:q.put(message) 信息放入队列
- receive:q.get() 获取队列信息
if __name__ == '__main__':
# 创建一个队列
q = multiprocessing.Queue()
# 实例化work类
work = Work(q)
# 定义一个传入的进程
# send = multiprocessing.Process(target=work.send, args=(1,2,3))
send = multiprocessing.Process(target=work.send, args=[{'name':'小慕'}])
# 定义一个接收的进程
recv = multiprocessing.Process(target=work.receive)
send_all_p = multiprocessing.Process(target=work.send_all)
send_all_p.start()
send.start()
recv.start()
send_all_p.join() # 阻塞最长使用率的进程
recv.terminate()
线程的创建
- threading:Thread(target, args) 创建线程(target是要执行的函数,args是执行这个函数需要传入的参数)
线程对象的方法 - 启动线程——start()
- 阻塞直到线程执行结束——join(timeout=None)
- 获取线程的名字——getName()
- 设置线程的名字——setName(name)
- 判断线程是否存活——is_alive()
- 守护线程——setDaemon(True)
定义一个列表A,再定义一个列表B,将A中的内容随机写到B中并删除随机的数据。
def work():
if len(lists) == 0:
return []
data = random.choice(lists) # 随机获取列表中的成员
lists.remove(data)
new_data = '%s_new' % data
lists_new.append(new_data)
time.sleep(1)
线程的问题
- 通过线程执行的函数无法获得返回值
- 多个线程同时修改文件可能造成数据错乱
- 线程池的创建——concurrent
futures.ThreasPoolExecutor
tpool = ThreadPoolExecutor(max_workers) #线程池对象 - 往线程池中加入任务:submit(target, args)
- 线程池中的某个线程是否完成了任务:done()
- 获取当前线程执行任务的结果:result()
GIL全局锁
- GIL的作用
- 使得python的多线程无法在多个cpu上执行任务,只能在单一cpu上执行任务,限制了多线程的任务,使得不那么多线程了;
- 保障线程之间的安全;pypy解释器不含有GIL锁;
- 使用多进程+多线程的方式弥补这一问题,通过使用多个进程在每个cpu跑道上执行任务,并且每个跑道上再执行多个线程,让他们去到各自的时间片上去运行。
- 总结多线程与多进程:在主进程或者主线程中创建多个子进程或者子线程,子进程或者子线程的运行不会影响主进程和主线程的代码执行,从而使得代码可以在多个线程或多个进程下提高代码质量。
异步
- 异步的目的是为了不阻塞。
异步属于轻量级的线程 协程,是进程下的一部分
多进程与多线程无法获取函数的返回值, 但是异步可以获取函数的返回值
主进程需要异步才可以使用异步
更适合文件读写使用
3. async和await关键字
async定义异步 async def test():
return ‘a’
await执行异步 async def handle():
result = await test()
asyncio调用saync函数
4. gevent
pip install gevent
Microsoft Visual C++
pip install wheel
spawn 创建协程对象 返回值是一个协程对象
joinall 批量处理协程对象