• 并发编程


    1.协程
    并发:切+保存状态
    单线程下实现并发:协程 切+ 保存状态 yield
    遇到io切,提高效率
    遇到计算切,并没有提高效率

    检测单线程下 IO行为 io阻塞 切
    相当于骗操作系统 一直处于计算
    协程:。。。
    单线程下实现并发:根本目标:遇到IO就切,一个线程的整体IO降下来
    程序用的cpu 时间长,就叫执行效率高
    效率最高:多个进程 (多个cpu)
    每个进程开多个线程
    每个线程用到协程 (IO就切)
    总结协程特点:
     1 #并发执行
     2 import time
     3 
     4 def producer():
     5     g=consumer()
     6     next(g)
     7     for i in range(10000000):  # 计算
     8         g.send(i)
     9 
    10 
    11 def consumer():
    12     while True:
    13         res=yield
    14 
    15 
    16 start_time=time.time()
    17 producer()
    18 stop_time=time.time()
    19 print(stop_time-start_time)
    20 
    21 #串行
    22 import time
    23 
    24 def producer():
    25     res=[]
    26     for i in range(10000000):
    27         res.append(i)
    28     return res
    29 
    30 
    31 def consumer(res):
    32     pass
    33 
    34 
    35 start_time=time.time()
    36 res=producer()
    37 consumer(res)
    38 stop_time=time.time()
    39 print(stop_time-start_time)
    2.greenlet模块
    pip3 install greenlet
    greenlet:可以很方便的切 但不能检测到 遇到IO 切
    greenlet 比yield 好 但是还是不好 遇到io不会切
     1 from greenlet import greenlet
     2 import time
     3 
     4 def eat(name):
     5     print('%s eat 1' %name)
     6     time.sleep(10)  # 遇到io 不会立即切
     7     g2.switch('egon')
     8     print('%s eat 2' %name)
     9     g2.switch()
    10 
    11 def play(name):
    12     print('%s play 1' %name )
    13     g1.switch()
    14     print('%s play 2' %name )
    15 
    16 
    17 g1=greenlet(eat)
    18 g2=greenlet(play)
    19 
    20 g1.switch('egon') # 第一次切 需要传参数
    3.gevent模块
    pip3 install gevent
    gevent:封装了greenlet模块,但是他能检测到io 自动切
    只能检测到gevent.sleep() gevent的IO阻塞
    加上补丁后,就可以检测到所有的IO 原理是:将阻塞变为非阻塞
    from gevent import monkey;monkey.patch_all()
    这种形式的协程 才能帮我们提升效率 从始至终 就一个线程
    gevent.joinall([g1,g2]) 等待全部执行完

    gevent 模块:监测单线程下多个任务得IO行为实现遇到IO就自动切到另一个任务去执行
    提升单线程运行效率
    应用场景:单线程下多个任务io密集型
    ftp io密集型 线程来回切 比os q切 小路高
     1 from gevent import monkey;monkey.patch_all()  # 一定要放在程序的开头 检测所以的io 将阻塞变成非阻塞
     2 import gevent
     3 import time
     4 
     5 
     6 def eat(name):
     7     print('%s eat 1' % name)
     8     time.sleep(3)  # 7s多一些 gevent 只识别 gevent 的 io操作
     9     # gevent.sleep(3)  # 4s 多一些
    10     print('%s eat 2' % name)
    11 
    12 
    13 def play(name):
    14     print('%s play 1' % name)
    15     time.sleep(4)
    16     # gevent.sleep(4)
    17     print('%s play 2' % name)
    18 
    19 
    20 start_time=time.time()
    21 g1=gevent.spawn(eat,'egon')
    22 g2=gevent.spawn(play,'alex')
    23 
    24 g1.join()
    25 g2.join()
    26 stop_time=time.time()
    27 print(stop_time-start_time)
    28 """
    29 egon eat 1
    30 alex play 1
    31 egon eat 2
    32 alex play 2
    33 4.001747369766235
    34 
    35 """
    36 """
    37 egon eat 1
    38 egon eat 2
    39 alex play 1
    40 alex play 2
    41 7.0017828941345215
    42 """
    43 """
    44 egon eat 1
    45 alex play 1
    46 egon eat 2
    47 alex play 2
    48 4.001675367355347
    49 """
    50 
    51 from gevent import monkey;monkey.patch_all()
    52 import gevent
    53 import time
    54 
    55 
    56 def eat(name):
    57     print('%s eat 1' % name)
    58     time.sleep(3)
    59     print('%s eat 2' % name)
    60 
    61 
    62 def play(name):
    63     print('%s play 1' % name)
    64     time.sleep(4)
    65     print('%s play 2' % name)
    66 
    67 
    68 g1=gevent.spawn(eat,'egon')  # 异步操作
    69 g2=gevent.spawn(play,'alex')
    70 
    71 # time.sleep(5)  # 得等到 全部执行完
    72 
    73 # g1.join()  # 等到 全部执行完
    74 # g2.join()
    75 
    76 gevent.joinall([g1,g2])  # 等到g1 g2 全部执行完
    77 """
    78 egon eat 1 
    79 alex play 1 
    80 egon eat 2 
    81 alex play 2  
    82 """
    4.gevent实现并发的套接字通信
    # 500 客户端同时 登录 服务端:这里1个线程 抗住了 500个client
    # 这里也说明了:单线程下面io问题降下来,效率大幅度提高

    说明
    使用:多进程
    多线程
    一个线程io 问题解决了 效率大大得提高
    服务端:
     1 #基于gevent实现
     2 from gevent import monkey,spawn;monkey.patch_all()
     3 from socket import *
     4 
     5 def communicate(conn):
     6     while True:
     7         try:
     8             data=conn.recv(1024)
     9             if not data:break
    10             conn.send(data.upper())
    11         except ConnectionResetError:
    12             break
    13 
    14     conn.close()
    15 
    16 def server(ip,port):
    17     server = socket(AF_INET, SOCK_STREAM)
    18     server.bind((ip,port))
    19     server.listen(5)
    20 
    21     while True:
    22         conn, addr = server.accept()
    23         spawn(communicate,conn)  # 这里没必要加join
    24 
    25     server.close()
    26 
    27 if __name__ == '__main__':
    28     g=spawn(server,'127.0.0.1',8090)
    29     g.join()
    客户端:
     1 from socket import *
     2 from threading import Thread,currentThread
     3 
     4 def client():  #
     5     client=socket(AF_INET,SOCK_STREAM)
     6     client.connect(('127.0.0.1',8090))
     7 
     8 
     9     while True:
    10         client.send(('%s hello' %currentThread().getName()).encode('utf-8'))
    11         data=client.recv(1024)
    12         print(data.decode('utf-8'))
    13 
    14     client.close()
    15 
    16  # 500 客户端同时 登录  服务端:这里1个线程 抗住了 500个client
    17  # 这里也说明了:单线程下面io问题降下来,效率大幅度提高
    18 if __name__ == '__main__':
    19     for i in range(500):  # 500 客户端同时 登录  服务端:这里1个线程 抗住了 500个client
    20         t=Thread(target=client)
    21         t.start()
  • 相关阅读:
    杭电 1521 排列组合

    杭电 1799 循环多少次?
    杭电1028 Ignatius and the Princess III(整数拆分)
    毕业论文A.1 Matlab环境配置
    Open Graphics Library初步_搭建环境_GLUT
    Open Graphics Library初步_摄影机_GLUT
    C#使用office相关com组件
    插入排序
    二叉树的四种遍历方法(递归、迭代)
  • 原文地址:https://www.cnblogs.com/alice-bj/p/8719143.html
Copyright © 2020-2023  润新知