协程实现多边同时交互原理

Posted dark-fire-liehuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了协程实现多边同时交互原理相关的知识,希望对你有一定的参考价值。

协程的好处:

在IO密集型的程序中由于IO操作远远慢于CPU的操作,所以往往需要CPU去等IO操作。 同步IO下系统需要切换线程,让操作系统可以在IO过程中执行其他的东西。 这样虽然代码是符合人类的思维习惯但是由于大量的线程切换带来了大量的性能的浪费,尤其是IO密集型的程序。

所以人们发明了异步IO。就是当数据到达的时候触发我的回调。来减少线程切换带来性能损失。 但是这样的坏处也是很大的,主要的坏处就是操作被 “分片” 了,代码写的不是 “一气呵成” 这种。 而是每次来段数据就要判断 数据够不够处理哇,够处理就处理吧,不够处理就在等等吧。这样代码的可读性很低,其实也不符合人类的习惯。

但是协程可以很好解决这个问题。比如 把一个IO操作 写成一个协程。当触发IO操作的时候就自动让出CPU给其他协程。要知道协程的切换很轻的。 协程通过这种对异步IO的封装 既保留了性能也保证了代码的容易编写和可读性。在高IO密集型的程序下很好。但是高CPU密集型的程序下没啥好处。

协成的简单实现greenlet:

关于greenlet实现代码:

调用时使用switch()

技术分享图片
from greenlet import greenlet
import time
def test1():
    while True:
        print(沉大器者得天下)
        gr2.switch()
        time.sleep(0.5)
def test2():
    while True:
        print(不拘小节)
        
        time.sleep(0.5)
    
gr1=greenlet(test1)
gr2=greenlet(test2)


gr1.switch()
    
View Code

 

gevent切换执行

  • gevent导入
  • 设置协程要执行的函数(任务)
  • gevent.spawn(协程要执行的函数,参数)实例化协程对象
  • g1.join()来阻塞主线程运转,直到协程运转完毕

gevent 协程的切换时根据是否有阻塞进行,而且这个阻塞需要gevent能够识别,如果是系统的,你需要加上monkey.patch_all()(gevent.sleep(1)  ----->>  如果是系统的time.sleep(1))

在此给出一个基础的演示代码:

技术分享图片
import gevent
from gevent import monkey
import time


def test1():
    list=[不要,小看,自己,也不要,大看,别人,放大心灵死角]
    n=len(list)
    while n>0:
        for i in list:
            print(i)
            gevent.sleep(1)
            n-=1

def test2():
    list=[人生,三件,大事,大事,中事,小事,你会溃烂在别人得眼眶里]
    n=len(list)
    while n>0:
        for i in list:
            print(i)
            gevent.sleep(1)
            n-=1

        
g1=gevent.spawn(test1)
g2=gevent.spawn(test2)

            
g1.join()
g2.join()
    
    
View Code

 

一个实例代码多线程服务端:

import gevent
from gevent import socket, monkey
import os

# 接收信息,并回复信息
def co(conn,IP):
    try:
        while True:
            # 接收信息并解码
            data = conn.recv(1024).decode(gbk)
            if data:

                print(收到%s:%s 信息:%s 进程:%s % (IP[0], IP[1],data, os.getpid()))
                # # 给客户端回复数据
                # conn.send(bthanks)
            else:
                conn.close()
                break
    finally:
        conn.close()



# 创建协程,并获取连接到的客户端信息,传输调用函数
def server(port):

    # 创建协程
    xc = socket.socket()
    # 绑定本地地址
    addr = (‘‘, port)
    xc.bind(addr)
    
    # 监听是否有客服端连接
    xc.listen(5)
    try:
        while True:
            #获取客户端连接的信息,并进行处理
            print(等待连接。。。)
            connent, ad = xc.accept()
            print(连接成功)
            # 调起一个协程,调用函数,对数据进行回复操作
            gevent.spawn(co, connent, ad)
            ‘‘‘
            运用协程,主要是想实现能同时和多个客户端进行信息交互
            因此,在这里不能调用join()方法(停止等待所有线程工作完后再继续)
            要不然就无法实现多边交互的功能了,
            ‘‘‘
            # g = gevent.spawn(co, connent,ad)
            # g.join()
    finally:
        xc.close()

if __name__==__main__:
    server(6969)
    # print(系统出现错误)

连接服务端的客户端:

from socket import *
import time

qqSocket=socket(AF_INET,SOCK_STREAM)

Addr=(192.168.8.195,6969)
# qqSocket.bind(Addr)

qqSocket.connect(Addr)
n=10000
while True:
    time.sleep(1)
    sendData=八戒 你瘦了 
    qqSocket.send(sendData.encode(gbk))

    if not sendData:
        break
    n-=1
    #
    #
    # recData=qqSocket.recv(1024)
    # print(收到服务端的回复:%s%recData.decode(gbk))


qqSocket.close()

 

以上是关于协程实现多边同时交互原理的主要内容,如果未能解决你的问题,请参考以下文章

聊一聊Unity协程背后的实现原理

聊一聊Unity协程背后的实现原理

聊一聊Unity协程背后的实现原理

Gevent的协程实现原理

GO GMP协程调度实现原理 5w字长文史上最全

进程线程和协程