并发编程 --进、线程池、协程、IO模型

内容目录:

  • 1.socket服务端实现并发
  • 2.进程池,线程池
  • 3.协程
  • 4.IO模型

1.socket服务端实现并发

# 客户端:
import socket

client = socket.socket()
client.connect(('127.0.0.1', 8080))
while True:
    data = input('>>>:').encode('utf-8')
    if len(data) == 0: continue
    client.send(data)
    res = client.recv(1024)
    print(res)
# 服务端:
"""
    1.固定的ip和端口
    2.24小时不间断提供服务
    3.支持高并发
"""
import socket
from threading import  Thread

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

def trans_data(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0: break
            print(data)
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()
    
while True:
    conn, addr = server.accept()
    print(addr)
    t = Thread(target=trans_data, args=(conn,))
    t.start()

2.进程池、线程池

"""
无论是开线程还是开进程,其实都会消耗资源,开线程消耗的资源比开进程的小
池:
    1.为了减缓计算机硬件的压力,避免计算机硬件设备崩溃
    2.虽然减轻了计算机硬件的压力,但一定程度上降低了持续的效率
    
进程池、线程池:
    为了限制开设的进程数和线程数,从而保证计算机硬件的安全
"""
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time

# 实例化池对象 --线程池
# 不指定参数的情况下,默认为当前计算机cpu个数乘以5,也可指定线程个数
pool1 = ThreadPoolExecutor(20)

# 实例化池对象 --进程池
# 不指定参数的情况下,默认为当前计算机cpu个数,也可指定进程个数
pool = ProcessPoolExecutor(20)
# pool = pool1  # 为了交换测试两种池

def task(n):
    print(n)
    time.sleep(2)
    return n**2

def call_back(n):
    print("拿到结果:%s" % n.result())

"""
提交任务的方式:
    同步:提交任务之后,等待任务执行返回结果之后,再进行下一步代码
    异步:提交任务之后,不等待任务的返回结果(通过回调函数返回结果),直接执行下一步操作
"""

# 回调函数:异步提交之后一旦任务有返回结果,自动交给另一个去执行
if __name__ == '__main__':
    # pool.submit(task,1)
    t_list = []
    for i in range(20):
        pool.submit(task, i).add_done_callback(call_back)  # 异步提交任务
        # t_list.append(future)

    pool.shutdown()  # 关闭池子并且等待池子中所有的任务运行完毕
    # for p in t_list:
    #     print('>>>:', p.result())
    print('主')

3.协程

"""
进程:资源单位(车间)
线程:最小执行单位(流水线)
协程:单线程,实现并发

并发:看上去像同时运行就可以称之为并发
多道技术:
    空间上的复用:硬件上的复用,内存中划分区域存放数据信息
    时间上的复用:快速切换
    
协程:认为创造的专业名词
    通过代码层面自己监测IO自己实现切换,让操作系统误以为你这个线程没有IO
    
切换+保存状态就一定能够提升程序效率吗?
    不一定,如果任务是计算密集型,反而会降低效率,如果任务是IO密集型,会提升效率。
"""
# 检测代码中所有的IO行为
from gevent import monkey;monkey.patch_all()
from gevent import spawn, joinall  # gevent 本身识别不了time.sleep等不属于该模块内的io操作
import time

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

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

start = time.time()
g1 = spawn(play, 'lisi')
g2 = spawn(eat, 'lisi')

# g1.join()
# g2.join()
joinall([g1, g2])
print('主', time.time() - start)  # 单线程下实现并发,提升效率
"""
# 运行结果:
lisi play 1
lisi eat 1
lisi eat 2
lisi play 2
主 2.013660192489624
"""

4.IO模型

"""
阻塞IO
非阻塞IO (服务端通信针对accept用s.setblocking(False)加异常捕获,cpu占用率过高)
IO多路复用
    在只检测一个套接字的情况下,他的效率连阻塞IO都比不上。因为select这个中间人增加了环节。
    但是在检测多个套接字的情况下,就能省去wait for data过程
异步IO
"""
posted @ 2019-05-30 08:25  xt12321  阅读(143)  评论(0编辑  收藏  举报