python练习19 -- 协程

协程:

  • 定义:微线程。是允许在不同入口点不同位置暂停或开始的计算机程序,简单说,携程就是可以暂停执行的函数。
  • 协程原理:记录一个函数的上下文,携程调度切换将记录的上下文保存,在切换回来时进行调取,恢复原有的执行内容,以便从上以此执行位置继续执行。

优点:

  • 携程完成多任务占用计算机资源很少
  • 由于协程的多任务切换在应用层完成,因此切换开销小
  • 协程为单线程序,无需进行共享资源同步互斥处理

缺点:协程的本质是一个单线程,无法利用计算机多核资源

greenlet模块

g=greenlet.green(func)

功能:创建协程对象。 参数:协程函数。

g.switch()

功能:选择要执行的协程函数 

示例gl_exer.py:

#!/bin/env python3

import greenlet

def fun1():
    print("executing fun1")
    gr2.switch()                   # 跳转到gr2执行
    print("finishing func1")
    gr2.switch()                   # 跳转到gr2执行


def fun2():
    print("executing fun2")
    gr1.switch()                   # 跳转到gr1执行
    print("finishing func2")


# 将函数变成协程
gr1 = greenlet.greenlet(fun1)   # 把fun1变成协程
gr2 = greenlet.greenlet(fun2)   # 把fun2变成协程
gr1.switch()                    # 执行协程gr1

执行结果:

[root@gyl-baidu python]# ./gl_exer.py
executing fun1
executing fun2
finishing func1
finishing func2

gevent模块:

gevent.spawn(func,argv)
功能:生产协程对象
参数:
        func 协程函数
        argv 给协程函数传参(不定参)
返回值:协程对象

gevent.joinall(list[,timeout])
功能:阻塞等待协程只能够完毕
参数:
        list 协程对象列表
        timeout 超时时间

gevent.sleep(sec)
功能:gevent睡眠阻塞
参数:睡眠时间

gevent协程只有遇到gevent指定的阻塞行为时才会自动在协程之间跳转
如果gevent.joinall() gevent.sleep()带来的阻塞

示例代码:gv_exer.py

#!/bin/env python3

import gevent

def add(a, b):
    print("Running add ...")
    print("%d + %d = %d" % (a, b, a + b))
    gevent.sleep(1)
    print("Finished add ...")


def sub(a, b):
    print("Running sub ...")
    print("%d - %d = %d" % (a, b, a - b))
    gevent.sleep(2)
    print("Finished sub ...")


g1 = gevent.spawn(add, 10, 2)
g2 = gevent.spawn(sub, 10, 2)

# gevent.sleep(1)
gevent.joinall([g1, g2])

执行结果:

[root@gyl-ali python3]# ./gv_exer.py
Running add ...
10 + 2 = 12
Running sub ...
10 - 2 = 8
Finished add ...
Finished sub ...

gevent中monkey脚本

 作用:在gevent协程中,协程只有遇到gevent指定类型的阻塞才能跳转到其它协程 因此,将普通的IO阻塞转为可以触发gevent协程的阻塞,以提高执行效率。 转换方法:gevent提供了一个脚本monkey,可以修改底层解释IO阻塞行为, 将很多普通阻塞转变为gevent阻塞。

用法:

  1. 1、从gevent导入monkey
  2. 2、 运行相应的脚本,例如,转换socket中所有阻塞 monkey.patch_socket() ,将所有可转换的IO阻塞,全部转换,则运行all monkey.patch_all()

示例代码m_server.py:

#!/bin/env python3
"""
基于协程的TCP并发服务端
"""

import gevent
from gevent import monkey

monkey.patch_all()
import socket


def handle(c):
    while True:
        data = c.recv(1024).decode()
        if not data:
            break
        print("client:", data)
        msg = "server: " + data
        c.send(msg.encode())


s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("0.0.0.0", 80))

s.listen(10)

while True:
    c, addr = s.accept()
    print("connect from ", addr)
    gevent.spawn(handle, c)

运行这个脚本并用两个客户端进行连接测试:

[root@gyl-ali python3]# chmod +x m_server.py
[root@gyl-ali python3]# ./m_server.py
connect from  ('192.168.1.10', 34958)
client: hello c1

connect from  ('192.168.1.20', 57468)
client: hello world
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值