zoukankan      html  css  js  c++  java
  • 协程和I/O模型

    1、协程:
    单线程实现并发
    在应用程序里控制多个任务的切换+保存状态
    优点:
    应用程序级别速度要远远高于操作系统的切换
    缺点:
    多个任务一旦有一个阻塞没有切换,整个线程都阻塞在原地
    该线程内的其他的任务都不能执行了

    一旦引入协程,就需要检测单线程下所有的IO行为,
    实现遇到IO就切换,少一个都不行,因为一旦一个任务阻塞了,整个线程就阻塞了,
    其他的任务即便是可以计算,但是也无法运行了

    2、协程的目的:
    想要在单线程下实现并发
    并发指的是多个任务看起来是同时运行的
    并发=切换+保存状态


     1 from gevent import monkey,spawn;monkey.patch_all()
     2 from threading import current_thread
     3 import time
     4 # 实现了单线程下的并发,遇到i/O就切换
     5 def eat():
     6     print('%s eat 1' %current_thread().name)
     7     time.sleep(3)
     8     print('%s eat 2' %current_thread().name)
     9 
    10 def play():
    11     print('%s play 1' %current_thread().name)
    12     time.sleep(1)
    13     print('%s play 2' %current_thread().name)
    14 
    15 start = time.time()
    16 g1=spawn(eat,)  # 创建一个协程对象
    17 g2=spawn(play,)
    18 
    19 print(current_thread().name)
    20 g1.join() # 也有join方法
    21 g2.join()
    22 
    23 stop = time.time()
    24 print(stop-start)
    25 
    26 # MainThread
    27 # DummyThread-1 eat 1  虚假线程
    28 # DummyThread-2 play 1
    29 # DummyThread-2 play 2
    30 # DummyThread-1 eat 2
    31 # 3.003624439239502
    单线程下的并发

    并发的套接字通信

     1 from gevent import spawn,monkey;monkey.patch_all()
     2 from socket import *
     3 from threading import Thread
     4 
     5 def talk(conn):
     6     while True:
     7         try:
     8             data=conn.recv(1024)  
     9             if len(data) == 0:break
    10             conn.send(data.upper())
    11         except ConnectionResetError:
    12             break
    13     conn.close()
    14 
    15 def server(ip,port,backlog=5):
    16     server = socket(AF_INET, SOCK_STREAM)
    17     server.bind((ip, port))
    18     server.listen(backlog)
    19 
    20     print('starting...')
    21     while True:
    22         conn, addr = server.accept()
    23         spawn(talk, conn,)  # 指定执行的任务,后面的conn是传入的参数
    24         
    25 
    26 if __name__ == '__main__':
    27     g=spawn(server,'127.0.0.1',8080) # 执行server
    28     g.join()
    服务端
     1 from threading import Thread,current_thread
     2 from socket import *
     3 import os
     4 
     5 def task():
     6     client=socket(AF_INET,SOCK_STREAM)
     7     client.connect(('127.0.0.1',8080))
     8 
     9     while True:
    10         msg='%s say hello' %current_thread().name
    11         client.send(msg.encode('utf-8'))
    12         data=client.recv(1024)
    13         print(data.decode('utf-8'))
    14 
    15 if __name__ == '__main__':
    16     for i in range(500):
    17         t=Thread(target=task)
    18         t.start()
    客户端

    网络IO:
    recvfrom:
    wait data:等待客户端产生数据——》客户端OS--》网络--》服务端操作系统缓存
    copy data:由本地操作系统缓存中的数据拷贝到应用程序的内存中

    send:
    copy data


    # conn.recv(1024) ==>OS

    非阻塞I/O模型

     1 from socket import *
     2 import time
     3 
     4 server = socket(AF_INET, SOCK_STREAM)
     5 server.bind(('127.0.0.1',8080))
     6 server.listen(5)
     7 server.setblocking(False)
     8 
     9 conn_l=[]
    10 while True:
    11     try:
    12         print('总连接数[%s]' % len(conn_l))
    13         conn,addr=server.accept()
    14         conn_l.append(conn)
    15     except BlockingIOError:
    16         del_l=[]
    17         for conn in conn_l:
    18             try:
    19                 data=conn.recv(1024)
    20                 if len(data) == 0:
    21                     del_l.append(conn)
    22                     continue
    23                 conn.send(data.upper())
    24             except BlockingIOError:
    25                 pass
    26             except ConnectionResetError:
    27                del_l.append(conn)
    28 
    29         for conn in del_l:
    30             conn_l.remove(conn)
    服务端
     1 from socket import *
     2 import os
     3 
     4 client=socket(AF_INET,SOCK_STREAM)
     5 client.connect(('127.0.0.1',8080))
     6 
     7 while True:
     8     msg='%s say hello' %os.getpid()
     9     client.send(msg.encode('utf-8'))
    10     data=client.recv(1024)
    11     print(data.decode('utf-8'))
    客户端



  • 相关阅读:
    PAT 1008--------数组元素的循环右移,你需要记住的
    PAT1049-----枚举法,找规律题,注意降低时间复杂度
    PAT1048----你需要了解并记住的解题思路
    C++中几个输入函数的用法和区别(cin、cin.get()、cin.getline()、getline()、gets()、getchar()))
    PAT1040----关于数学题目的解法新思路值得借鉴,字符的配对
    PAT1029-----介绍字符串的解题思路和部分知识点
    PAT1027-----等差数列的问题或数学问题
    PAT1026----四舍五入的思路,%2d的一些知识
    / 已阅 /PAT1017-------高精度计算,问题的所有可能情况
    LeetCode 无重复字符的最长子串
  • 原文地址:https://www.cnblogs.com/Roc-Atlantis/p/9325650.html
Copyright © 2011-2022 走看看