05并发编程 ( GIL+进程池与线程池+协程+IO模型 )

并发编程

进程池与线程池基本使用

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time
import os

# 创建进程池与线程池
# pool = ThreadPoolExecutor(5)  # 可以自定义线程数 也可以采用默认策略
pool = ProcessPoolExecutor(5)  # 可以自定义线程数 也可以采用默认策略


# 定义一个任务
def task(n):
    print(n, os.getpid())
    time.sleep(2)
    return '>>>:%s' % n ** 2


# 定义一个回调函数:异步提交完之后有结果自动调用该函数
def call_back(a):
    print('异步回调函数:%s' % a.result())


# 朝线程池中提交任务
# obj_list = []
for i in range(20):
    res = pool.submit(task, i).add_done_callback(call_back)  # 异步提交
    # obj_list.append(res)
"""
同步:提交完任务之后原地等待任务的返回结果 期间不做任何事
异步:提交完任务之后不愿地等待任务的返回结果 结果由异步回调机制自动反馈
"""
# 等待线程池中所有的任务执行完毕之后 再获取各自任务的结果
# pool.shutdown()
# for i in obj_list:
#     print(i.result())  # 获取任务的执行结果  同步

在windows电脑中如果是进程池的使用也需要在__main__下面

协程理论与实操

进程
	资源单位
线程
	工作单位
协程
	是程序员单方面意淫出来的名词>>>:单线程下实现并发

# CPU被剥夺的条件
	1.程序长时间占用
	2.程序进入IO操作
# 并发
	切换+保存状态
  	以往学习的是:多个任务(进程、线程)来回切换
# 欺骗CPU的行为
	单线程下我们如果能够自己检测IO操作并且自己实现代码层面的切换
  那么对于CPU而言我们这个程序就没有IO操作,CPU会尽可能的被占用
  
"""代码层面"""
第三方gevent模块:能够自主监测IO行为并切换
from gevent import monkey;monkey.patch_all()  # 固定代码格式加上之后才能检测所有的IO行为
from gevent import spawn
import time


def play(name):
    print('%s play 1' % name)
    time.sleep(5)
    print('%s play 2' % name)


def eat(name):
    print('%s eat 1' % name)
    time.sleep(3)
    print('%s eat 2' % name)


start = time.time()
# play('jason')  # 正常的同步调用
# eat('jason')  # 正常的同步调用
g1 = spawn(play, 'jason')  # 异步提交
g2 = spawn(eat, 'jason')  # 异步提交
g1.join()
g2.join()  # 等待被监测的任务运行完毕
print('主', time.time() - start)  # 单线程下实现并发,提升效率

协程实现TCP服务端并发的效果

# 并发效果:一个服务端可以同时服务多个客户端
import socket
from gevent import monkey;monkey.patch_all()
from gevent import spawn
def talk(sock):
    while True:
        try:
            data = sock.recv(1024)
            if len(data) == 0:break
            print(data)
            sock.send(data+b'hello baby!')
        except ConnectionResetError as e:
            print(e)
            sock.close()
            break
def servers():
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen()
    while True:
        sock, addr = server.accept()
        spawn(talk,sock)
g1 = spawn(servers)
g1.join()
# 客户端开设几百个线程发消息即可
"""
最牛逼的情况:多进程下开设多线程 多线程下开设协程
	我们以后可能自己动手写的不多 一般都是使用别人封装好的模块或框架
"""

IO模型简介

"""理论为主 代码实现大部分为伪代码(没有实际含义 仅为验证参考)"""
IO模型研究的主要是网络IO(linux系统)

# 基本关键字
  同步(synchronous)	大部分情况下会采用缩写的形式  sync
  异步(asynchronous) async
  阻塞(blocking) 
  非阻塞(non-blocking)
 
# 研究的方向
Stevens在文章中一共比较了五种IO Model:
    * blocking IO           阻塞IO
    * nonblocking IO      	非阻塞IO
    * IO multiplexing      	IO多路复用
    * signal driven IO     	信号驱动IO
    * asynchronous IO    		异步IO
    由signal driven IO(信号驱动IO)在实际中并不常用,所以主要介绍其余四种IO Model

四种IO模型简介

# 1.阻塞IO
	最为常见的一种IO模型 有两个等待的阶段(wait for data、copy data)
# 2.非阻塞IO
	系统调用阶段变为了非阻塞(轮训) 有一个等待的阶段(copy data)
  	轮训的阶段是比较消耗资源的
# 3.多路复用IO
	利用select或者epoll来监管多个程序 一旦某个程序需要的数据存在于内存中了 那么立刻通知该程序去取即可
# 4.异步IO
	只需要发起一次系统调用 之后无需频繁发送 有结果并准备好之后会通过异步回调机制反馈给调用者
posted @ 2022-02-10 22:07  Panda_Xin  阅读(24)  评论(0编辑  收藏  举报