网络并发5

进程池与线程池基本使用

        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-01-26 10:55  丶祈安  阅读(26)  评论(0编辑  收藏  举报