zoukankan      html  css  js  c++  java
  • 协程,IO模式

    1、协程(别人的模块,达到单线程并发效果)

    程序的运行状态:

    阻塞:

    IO阻塞

    非阻塞:

    运行

    就绪

    单线程实现并发:

    在应用程序里控制多个任务的切换+保存状态

    可以把IO减下来,但是不可能降到无

    优点:

    应用程序级别速度要远远高于操作系统的切换

    缺点:

    多个任务一旦有一个阻塞没有切,整个县城都堵塞在原地

    该线程内的其他的任务都不能执行

    一旦引入协程,就需要检测单线程下素有的IO行为,

    实现遇到IO就切换,少一个都不行,因为一旦一个任务阻塞,整个线程就 阻塞,其他的任务即便是可以计算,但是也无法运行。

    2、用协程的目的

    想要在单线程下实现并发

    并发指的是多个任务看起来是同时运行的

    并发=切换+保存状态

    线程在进程内,进程在操作系统内,一切由操作系统控制

    自己设置python程序让线程形成切换,不用操作系统控制。

    协程只有单线程下遇到IO切换才会提成效率,操作系统相对与协程要更慢点

    import time
    
    def func1():
        for i in range(1000000):
            i+1
    def func2():
        for i in range(1000000):
            i+1
    start = time.time()
    func1()
    func2()
    stop=time.time()
    print(stop-start)
    
    # 基于yield并发
    import time
    def func1():
        while True:
            print("func1")
            yield
    def func2():
        g=func1()
        for i in range(1000000):
            print("func2")
            i+1
            time.sleep(3)
            next(g)
    
    start=time.time()
    func2()
    stop=time.time()
    print(stop-start)
    串行执行:
    from gevent import monkey,spawn;monkey.patch_all()#monkey.patch_all()补丁
    import time
    
    def eat(name):
        print("%s eat 1" %name)
        time.sleep(3)
        print("%s eat 2" %name)
    def play(name):
        print("%s play 1" %name)
        time.sleep(1)
        print("%s play 2" %name)
    
    start=time.time()
    g1=spawn(eat,"yf")#自动运行任务 模块
    g2=spawn(play,"fxc")
    
    g1.join()#通过补丁让join识别其他IO
    g2.join()
    print(time.time() - start)
    print(g1)
    print(g2)
    
    
    from gevent import monkey,spawn;monkey.patch_all()
    from threading import current_thread
    import time
    
    def eat(name):
        print("%s eat 1" %current_thread().name)#都是一个线程,前面有dummy假标明
        time.sleep(3)
        print("%s eat 2" %current_thread().name)
    def play(name):
        print("%s play 1" %current_thread().name)
        time.sleep(1)
        print("%s play 2" %current_thread().name)
    
    start=time.time()
    g1=spawn(eat,"yf")
    g2=spawn(play,"fxc")
    
    g1.join()
    g2.join()
    print(time.time() - start)
    print(g1)
    print(g2)
    与yield类似可以直接计算的 gevent

    并发的套接字通信:

    from gevent import spawn,monkey;monkey.patch_all()
    from socket import *
    from threading import Thread
    
    def talk(conn):
        while True:
            try:
                data = conn.recv(1024)
                if len(data)==0:break
                conn.send(data.upper())
            except ConnectionResetError:
                break
        conn.close()
    
    def server(ip,port,backlog=5):
        server = socket(AF_INET,SOCK_STREAM)
        server.bind((ip,port))
        server.listen(backlog)
    
        print("starting..")
        while True:
            conn,addr=server.accept()
            spawn(talk,conn)
    if __name__ == '__main__':
        g=spawn(server,"127.0.0.1",8080)
        g.join()
    服务器:
    from threading import Thread,current_thread
    from socket import *
    
    def task():
        client = socket(AF_INET,SOCK_STREAM)
        client.connect(("127.0.0.1",8080))
        while True:
            msg="%s say hello" %current_thread().name
            client.send(msg.encode("utf-8"))
            data=client.recv(1024)
            print(data.decode("utf-8"))
    
    if __name__ == '__main__':
        for i in range(500):
            t=Thread(target=task)
            t.start()
    客户端:

    网络IO:

        recvfrom:#等待客户链接请求

            wait data:等待客户端产生数据——》客户端OS--》网络--》服务端操作系统缓存

            copy data:由本地操作系统缓存中的数据拷贝到应用程序的内存中

        send:

            copy data

    conn.recv(1024) ==>OS

    from socket import *
    import time
    
    server = socket()
    server.bind(("127.0.0.1",8080))
    server.listen(5)
    server.setblocking(False)#是否有链接过来
    
    conn_l=[]
    while True:
        try:
            print("总连接数[%s]" %len(conn_l))
            conn,addr=server.accept()
            conn_l.append(conn)
        except BlockingIOError:
            del_l=[]
            for conn in conn_l:
                try:
                    data=conn.recv(1024)
                    if len(data)==0:
                        del_l.append(conn)
                        continue
                    conn.send(data.upper())
                except BlockingIOError:
                    pass
                except ConnectionResetError:
                    del_l.append(conn)
            for conn in del_l:
                conn_l.remove(conn)
    服务端:
    from socket import *
    import os
    
    client=socket(AF_INET,SOCK_STREAM)
    client.connect(("127.0.0.1",8080))
    while True:
        msg="%s say hello" %os.getpid()
        client.send(msg.encode("utf-8"))
        data=client.recv(1024)
        print(data.dacoda("utf-8"))
    客户端:
  • 相关阅读:
    Linux基础--安装搭建tomcat+java+mysql
    使用ArcGIS JavaScript API 3.18 加载天地图
    关于ArcGIS的Web 3D GIS问答
    ArcGIS 10.5新功能预览
    如何选择合适分辨率的遥感影像
    如何正确响应ArcGIS JavaScript API中图形的鼠标事件
    安装Portal for ArcGIS时如何正确配置HTTPS证书
    ArcGIS地图文档优化 mxdPerfstat工具使用体验
    Web AppBuilder Widget使用共享类库的方式
    如何通过ArcMap Add-in机制实现十字叉线地理配准工具
  • 原文地址:https://www.cnblogs.com/yf18767106368/p/9325944.html
Copyright © 2011-2022 走看看