协程/IO多路复用

一.协程:

概念:是一个比线程更加轻量级的单位,是组成线程的各个函数

为什么要有协程:

想要在单线程内实现并发的效果.但因为Cpython有GIL锁,限制了在同一时间点,CPU只能执行一个线程,所以想要在执行一个线程的期间,充分利用cpu的性能,所以才有了想在单线程内实现并发的效果

cpu 为什么要切换:

  1.因为某个程序阻塞

  2.因为某个程序用完了时间片

  很明显,解决1 这个问题才能提高效率

所以想要实现单线程的并发,就要解决在单线程中,多个任务函数中,某个任务函数遇见IO操作,马上自动切换到其他任务函数去执行

greenlet模块:

能简单的是实现函数与函数之间的切换,但是遇到IO操作,不能自动切换到其他函数中

(1) 注册一下函数func,将函数注册成一个对象f1
    f1 = greenlet(func)
(2) 调用func,使用f1.switch(),如果func需要传参,就在switch里传

from greenlet import greenlet
import time

def eat(name):
    print(name,‘吃炸鸡‘)
    # time.sleep(1)
    f2.switch(‘张三‘)
    print(name,‘吃雪糕‘)
    f2.switch()

def drink(name):
    print(name,‘喝啤酒‘)
    f1.switch()
    print(name,‘喝可乐‘)

f1 = greenlet(eat)
f2 = greenlet(drink)
f1.switch(‘晓雪‘)
greenlet

gevent 模块:

可以实现在某函数内部遇到IO操作,就自动的切换到其他函数内部去执行

g = gevent.spawn(func,参数) 注册函数func,返回一个对象g
gevent.join(g) 等待g指定的func函数执行完毕,如果执行过程中,遇到IO切换
gevent.joinall([g1,g2,g3]) 等待g1,g2,g3指向的函数func执行完毕

import gevent
import time
from gevent import monkey
monkey.patch_all()

def func():
    print(123)
    time.sleep(1)
    print(345)
    # time.sleep(1)

def func1():
    print(456)
    time.sleep(2)
    print(567)
    # time.sleep(1)

g1 = gevent.spawn(func)
g2 = gevent.spawn(func1)
g1.join()
g2.join()

总结:进程,线程,协程

协程:是由用户自己去调度的,

计算密集用多进程,可以充分利用多核CPU的性能,IO密集用多线程

多线程和协程的区别:

线程是程序系统调度,控制

协程是程序员自己调度,控制

二.IO多路复用:

1.用非阻塞IO模型解决阻塞IO

服务端:import socket
sk = socket.socket()
sk.setblocking(False)
sk.bind((‘127.0.0.1‘,8080))
sk.listen()

l = []
del_l = []
while 1:
    try:
        conn,addr = sk.accept()# 如果是阻塞IO模型,在这里程序会一直等待。
        l.append(conn)# 将每个请求连接的客户端的conn添加到列表中
    except BlockingIOError:
        for conn in l:# 去遍历所有客户端的conn,看看有没有客户端给我发送数据了

            try:
                info = conn.recv(1024).decode(‘utf-8‘)# 尝试接收,看看有没有客户端给我发数据
                if not info:# 如果客户端正常执行了close,服务器会接收到一个空
                    del_l.append(conn)# 将已经结束的客户端的conn,添加到要删除的列表中
                    print(‘客户端正常退出了!‘)
                    conn.close()# 因为客户端已经主动close,所以服务器端的conn也要close
                else:
                    print(info)
                    conn.send(info.upper().encode(‘utf-8‘))
            except BlockingIOError:
                continue# 是没有接受到客户端发来的数据而报错
            except ConnectionResetError:
                pass# 是因为客户端强制退出而报错
        if del_l:
            for conn in del_l:
                l.remove(conn)
            del_l = []# 在删除完主动关闭的客户端的连接之后,应该把此列表清空,否则报错

2.基于select的网络IO模型

服务端:import select
import socket

sk = socket.socket()
sk.bind((‘127.0.0.1‘,8000))
sk.listen()
del_l = []
rlist = [sk]# 是用来让select帮忙监听的 所有 接口
# select:windows/linux是监听事件有没有数据到来
# poll:  linux   也可以做select的工作
# epoll: linux   也可以做类似的工作
while 1:
    r,w,x = select.select(rlist,[],[])# 传参给select,当rlist列表中哪个接口有反应,就返回给r这个列表
    # if r:
    for i in r:# 循环遍历r,看看有反应的接口到底是sk  还是conn
        if i == sk:
            # 如果是sk,那就表示有客户端的连接请求
            ‘‘‘sk有数据要接收,代表着有客户端要来连接‘‘‘
            conn,addr = i.accept() #添加if的意思是conn 没有accept sk才有 conn接收数据 所以有if
            rlist.append(conn)# 把新的客户端的连接,添加到rlist,继续让select帮忙监听
        else:
            # 如果是conn,就表示有客户端给我发数据了
            ‘‘‘conn有数据要接收,代表要使用recv‘‘‘
            try:
                msg_r = i.recv(1024).decode(‘utf-8‘)
                if not msg_r:
                    ‘‘‘客户端执行了close,客户端主动正常关闭连接‘‘‘
                    del_l.append(i)
                    i.close()
                else:
                    print(msg_r)
                    i.send(msg_r.upper().encode(‘utf-8‘))
            except ConnectionResetError:
                pass
        if del_l:# 删除那些主动断开连接的客户端的conn
            for conn in del_l:
                rlist.remove(conn)
            del_l.clear()

import socket
sk = socket.socket()
sk.connect((‘127.0.0.1‘,8080))

while 1:
    msg_s = input(‘>>>‘)
    if not msg_s:continue
    if msg_s == ‘q‘:break
    sk.send(msg_s.encode(‘utf-8‘))
    print(sk.recv(1024).decode(‘utf-8‘))
sk.close()

客户端

原文地址:https://www.cnblogs.com/ITdong-1/p/9550693.html

时间: 2024-10-10 03:14:00

协程/IO多路复用的相关文章

python_day10 多线程 协程 IO模型

多线程协程IO模型 多线程 #线程的PID与主进程PID一致 from threading import Thread from multiprocessing import Process import os def task(): print('%s is running' %os.getpid()) if __name__ == '__main__': t1=Thread(target=task,) t2=Thread(target=task,) # t1=Process(target=t

# 进程/线程/协程 # IO:同步/异步/阻塞/非阻塞 # greenlet gevent # 事件驱动与异步IO # Select\Poll\Epoll异步IO 以及selectors模块 # Python队列/RabbitMQ队列

1 # 进程/线程/协程 2 # IO:同步/异步/阻塞/非阻塞 3 # greenlet gevent 4 # 事件驱动与异步IO 5 # Select\Poll\Epoll异步IO 以及selectors模块 6 # Python队列/RabbitMQ队列 7 8 ############################################################################################## 9 1.什么是进程?进程和程序之间有什么

python协程io自动切换--gevent

1.gevent执行 import gevent def func1(): print('func1 start') gevent.sleep(2) print('func1 end') def func2(): print('func2 start') gevent.sleep(1) print('func2 end') def func3(): print('func3 start') gevent.sleep(0) print('func3 end') if __name__=='__ma

Python_oldboy_自动化运维之路_线程,进程,协程(十一)

本节内容: 线程 进程 协程 IO多路复用 自定义异步非阻塞的框架 线程和进程的介绍: 举个例子,拿甄嬛传举列线程和进程的关系: 总结:1.工作最小单元是线程,进程说白了就是提供资源的 2.一个应用程序至少有一个进程,一个进程里至少有一个线程 3.应用场景:io密集型适合用多线程,计算密集型(cpu)适合用多进程 4.GIL:全局解释器锁,作用:保证同一个进程中只能有一个线程同时被调用 5.python的一个诟病:前提是被cpu调度,因为有GIL,一个应用只有一个进程,纵容有多个线程,也体现不出

python进程、线程、协程、IO多路复用

线程进程介绍 工作最小单元是线程 应用程序 -> 至少有一个进程 -> 至少有一个线程 应用场景: IO密集型:线程 计算密集型:进程 4. GIL,全局解释器锁. 保证同一个进程中只有一个线程同时被调度 线程 1. 基本使用 def task(arg): time.sleep(arg) print(arg) for i in range(5): t = threading.Thread(target=task,args=[i,]) # t.setDaemon(True) # 主线程终止,不等

协程相关

---恢复内容开始--- 思想 主要的思想:如果一个变量自己有某种方法,而你想在不改变调用方式的前提下,希望可以点出它本身不存在的方法,就要想到用 类 封装的思想 , 将这个变量,改变为一个类的对象,在类中增加你需要的方法例如: # lst1= [1,2,3,4]#有append 的功能# lst2= [1,2,3,4]#有append 的功能# lst3= [1,2,3,4]#有append 的功能# lst4= [1,2,3,4]#有append 的功能# l = [lst1,lst2,ls

No.36协程

No.36 今日概要 协程 gevent模块 asyncio模块 内容回顾 1.锁 互斥锁 一把锁不能在一个线程中连续acquire 开销小 递归锁 一把锁可以在一个线程中连续acquire多次,acquire多少次就release多少次. 开销大 死锁现象 在线程中陷入阻塞并且永远无法结束阻塞的情况 形成原因 多把锁 + 交替使用 互斥锁在一个线程中连续acquire 避免死锁 在一个线程中只用一把锁,并且每一次acquire之后都要release. 线程中导致数据不安全的情况 += .-=

状态机/迭代器/LINQ/协程

状态机 有限状态机(Finite State Machine 或 Finite State Automata)是软件领域中一种重要的工具. 状态机允许一个对象在其内部状态改变时改变它的行为.对象内部状态决定行为方式,对象状态改变行为方式改变,这里强调内部状态. Command 模式是将命令请求封装成一个为对象,将不同的请求对象参数化以达到同样的调用执行不同的命令: State 模式是将对象的状态封装成一个对象,是在不同的状态下同样的调用执行不同的操作. 迭代器是一个典型的状态机例子,后续会讲解.

Python-线程池、进程池,协程

线程池&进程池 在python2中没有提供,在python3之后才提供 作用:保证程序中最多可以创建的线程的个数 import time from concurrent.futures import ThreadPoolExecutordef task(n1,n2):    time.sleep(1)    print('星空不问赶路人')pool = ThreadPoolExecutor(10) # 创建线程池for i in range(100):    pool.submit(task,i