【python学习笔记】第12天

这两天没有更新博客,但是学习依然在进行中,fighting!!

今日学习关键词:协程,greenlet,gevent

首先讲到了协程,协程是什么?

我的理解,协程也是一种多任务的实现方式,但他和多线程多进程不同的是,他是通过函数间的切换来实现并发的。

协程的效率:因为协程是在单个线程或进程内部执行,不需要保存各种信息(PID等),也不需要单独去占用cpu,所以可以在某些方面协程的效率要更高。

那么用python如何去实现协程呢,很简单,协程的原理就是生成器(generator),看下面代码:

import time

def test1():
    while True:
        print("----A----")
        yield
        time.sleep(0.5)

def test2(c):
    while True:
        print("----B----")
        c.__next__()
        time.sleep(0.5)

if __name__ == "__main__":
    A = test1()
    test2(A)

运行结果:

----B----
----A----
----B----
----A----
----B----
----A----
----B----
----A----
----B----
----A----
...

首先创建一个生成器对象A,然后调用test2函数,执行到c.__next__()时会跳到test1,而后执行到yield时会继续test2,以此类推

但是由于这个版本并不是那么的好看(毕竟我们用的是python,提升逼格用模块),我们引入greenlet模块

from greenlet import greenlet
import time

def test1():
    while True:
        print("----A----")
        pr2.switch()
        time.sleep(0.5)

def test2():
    while True:
        print("----B----")
        pr1.switch()
        time.sleep(0.5)
        
if __name__ == "__main__":
    pr1 = greenlet(test1)
    pr2 = greenlet(test2)

    pr1.switch()

运行结果:

----A----
----B----
----A----
----B----
----A----
----B----
----A----
----B----
----A----
...

创建两个greenlet对象,然后先从pr1开始执行,两个函数之间进行切换。

接下来就是更高逼格的东西,引入了gevent模块

import gevent

def f(n):
    for i in range(n):
        print(gevent.getcurrent(), i)

gv1 = gevent.spawn(f, 5)
gv2 = gevent.spawn(f, 5)
gv3 = gevent.spawn(f, 5)
gv1.join()
gv2.join()
gv3.join()

运行结果:

<Greenlet "Greenlet-0" at 0x7fdaafe38b48: f(5)> 0
<Greenlet "Greenlet-0" at 0x7fdaafe38b48: f(5)> 1
<Greenlet "Greenlet-0" at 0x7fdaafe38b48: f(5)> 2
<Greenlet "Greenlet-0" at 0x7fdaafe38b48: f(5)> 3
<Greenlet "Greenlet-0" at 0x7fdaafe38b48: f(5)> 4
<Greenlet "Greenlet-1" at 0x7fdaafe38e48: f(5)> 0
<Greenlet "Greenlet-1" at 0x7fdaafe38e48: f(5)> 1
<Greenlet "Greenlet-1" at 0x7fdaafe38e48: f(5)> 2
<Greenlet "Greenlet-1" at 0x7fdaafe38e48: f(5)> 3
<Greenlet "Greenlet-1" at 0x7fdaafe38e48: f(5)> 4
<Greenlet "Greenlet-2" at 0x7fdaaeb8b048: f(5)> 0
<Greenlet "Greenlet-2" at 0x7fdaaeb8b048: f(5)> 1
<Greenlet "Greenlet-2" at 0x7fdaaeb8b048: f(5)> 2
<Greenlet "Greenlet-2" at 0x7fdaaeb8b048: f(5)> 3
<Greenlet "Greenlet-2" at 0x7fdaaeb8b048: f(5)> 4

WTF?为什么是一个一个执行的?

其实在gevent模块当中有一个机制,它会自动判断是否有延时操作,如果有延时操作它才会在函数之间进行切换,所以我们加入延时操作之后再看结果:

import gevent

def f(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        gevent.sleep(0.5)

gv1 = gevent.spawn(f, 5)
gv2 = gevent.spawn(f, 5)
gv3 = gevent.spawn(f, 5)
gv1.join()
gv2.join()
gv3.join()

运行结果:

<Greenlet "Greenlet-0" at 0x7f84a1deeb48: f(5)> 0
<Greenlet "Greenlet-1" at 0x7f84a1deee48: f(5)> 0
<Greenlet "Greenlet-2" at 0x7f84a0b41048: f(5)> 0
<Greenlet "Greenlet-0" at 0x7f84a1deeb48: f(5)> 1
<Greenlet "Greenlet-1" at 0x7f84a1deee48: f(5)> 1
<Greenlet "Greenlet-2" at 0x7f84a0b41048: f(5)> 1
<Greenlet "Greenlet-0" at 0x7f84a1deeb48: f(5)> 2
<Greenlet "Greenlet-1" at 0x7f84a1deee48: f(5)> 2
<Greenlet "Greenlet-2" at 0x7f84a0b41048: f(5)> 2
<Greenlet "Greenlet-0" at 0x7f84a1deeb48: f(5)> 3
<Greenlet "Greenlet-1" at 0x7f84a1deee48: f(5)> 3
<Greenlet "Greenlet-2" at 0x7f84a0b41048: f(5)> 3
<Greenlet "Greenlet-0" at 0x7f84a1deeb48: f(5)> 4
<Greenlet "Greenlet-1" at 0x7f84a1deee48: f(5)> 4
<Greenlet "Greenlet-2" at 0x7f84a0b41048: f(5)> 4

这下解决了,但是要注意sleep是gevent模块的而不是time模块的。其实在gevent模块当中包含了一些其他带有延时功能模块的方法,接下来我们利用gevent来搭建一个tcp服务器:

import gevent

from gevent import socket, monkey

#这句话必须执行,会自动更改代码
monkey.patch_all()

def handle_request(conn):
    while True:
        data = conn.recv(1024)
        if not data:
            conn.close()
            break
        print("recv", data)
        conn.send(data)

def server(port):
    s = socket.socket()
    s.bind(("", port))
    s.listen(5)
    while True:
        cli, Addr = s.accept()
        gevent.spawn(handle_request, cli)

if __name__ == "__main__":
    server(7788)

这个代码就是老师课件上的代码,可以发现在gevent中也有socket。原理和之前学习的TCP一样,在这里不过多记录,但是要注意,必须在代码前加上那句monkey.patch_all(),否则会出现错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值