并发编程之 协程

协程 (单线程下实现并发)

  进程:资源单位

  线程:执行单位

  协程:单线程下实现并发

并发:切换+保存状态

程序员自己通过代码自己检测程序中的IO

一旦遇到了IO自己通过代码切换

给操作系统的感觉就是你这个线程没有任何的IO    从而提升代码的运行效率

 

切换+保存状态一定能够提升效率吗?

  1.当任务是IO密集型的情况下     提升效率

     2.当任务是计算密集型的情况下    降低效率

 

接下来 我们进行验证  

1.在计算密集型的情况下,通过切换+保存状态   效率到底是降低了还是提升了呢?

这是串行执行的时间:

复制代码
# 串行执行 0.8540799617767334
import time

def func1():
    for i in range(10000000):
        i+1

def func2():
    for i in range(10000000):
        i+1

start = time.time()
func1()
func2()
stop = time.time()
print(stop - start)
复制代码

下面是切换+保存状态的执行时间:

复制代码
#基于yield并发执行  1.3952205181121826
import time
def func1():
    while True:
        10000000+1
        yield

def func2():
    g=func1()
    for i in range(10000000):
        time.sleep(100)  # 模拟IO,yield并不会捕捉到并自动切换
        i+1
        next(g)

start=time.time()
func2()
stop=time.time()
print(stop-start)
复制代码

根据执行时间来看  明显效率是降低了

2.在IO密集型的情况下,通过切换+保存状态   效率到底是降低了还是提升了呢?

首先我们需要找到一个能够识别IO的工具,遇到IO就可以自动的切换

这里我们就用到了gevent模块

这是串行的执行结果:

 

复制代码
from gevent import monkey;monkey.patch_all()
from gevent import spawn
import  time

'''
注意  gevent模块没办法自动识别 time.sleep 等io情况
需要你手动配置一个参数
'''

def heng():
    print('哼!')
    time.sleep(2)
    print('哼!')

def ha():
    print('哈!')
    time.sleep(3)
    print('哈!')

start = time.time()

heng()
ha()

print(time.time()-start)
#5.041796445846558
复制代码

 

下面是通过切换+保存状态来执行  利用gevent模块

复制代码
from gevent import monkey;monkey.patch_all()
from gevent import spawn
import  time

'''
注意  gevent模块没办法自动识别 time.sleep 等io情况
需要你手动配置一个参数
'''

def heng():
    print('哼!')
    time.sleep(2)
    print('哼!')

def ha():
    print('哈!')
    time.sleep(3)
    print('哈!')

start = time.time()

g= spawn(heng)
g1 = spawn(ha)
g.join()
g1.join()

print(time.time()-start)

#3.041301727294922
复制代码

明显的看出在IO密集型的情况下  切换+保存状态能够提升效率

 

Gevent应用举例 

利用协程实现并发

实现TCP服务端的并发

server端

复制代码
import socket
from gevent import monkey;monkey.patch_all()
from gevent import spawn

sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()
def talk(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0 :break
            print(data.decode('utf-8'))
            conn.send(b'hi')
        except ConnectionResetError as e:
            print(e)
            break
    conn.close()

def server():
    while True:
        conn,addr = sk.accept()
        spawn(talk,conn)

if __name__ == '__main__':
    res = spawn(server)
    res.join()
复制代码

client端 起了400个线程

复制代码
from threading import Thread
import socket

def client():
    sk = socket.socket()
    sk.connect(('127.0.0.1',8080))


    while True:
        sk.send(b'hello')
        data = sk.recv(1024).decode('utf-8')
        print(data)

for i in range(400):
    t = Thread(target=client)
    t.start()
复制代码

 

posted @   s686编程传  阅读(135)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示