python gevent协程模块详解

简介: python gevent协程模块详解

python 模块 gevent 协程

文章目录

python 模块 gevent 协程

1. 进程、线程、协程区分

1.1 进程和协程

1.2 线程和协程

2. 简介

2.1 greenlets

3. 特点

4. 安装

5. 示例

5.1 用greenlet执行一个函数

5.2 创建协程任务

5.3 同步和异步执行

5.4 同步vs异步

1. 进程、线程、协程区分

我们通常所说的协程Coroutine其实是corporate routine的缩写,直接翻译为协同的例程,一般我们都简称为协程。

在linux系统中,线程就是轻量级的进程,而我们通常也把协程称为轻量级的线程即微线程。

1.1 进程和协程

下面对比一下进程和协程的相同点和不同点:


相同点:


相同点存在于,当我们挂起一个执行流的时,我们要保存的东西:

栈, 其实在你切换前你的局部变量,以及要函数的调用都需要保存,否则都无法恢复 寄存器状态,这个其实用于当你的执行流恢复后要做什么

而寄存器和栈的结合就可以理解为上下文,上下文切换的理解:

CPU看上去像是在并发的执行多个进程,这是通过处理器在进程之间切换来实现的,操作系统实现这种交错执行的机制称为上下文切换


操作系统保持跟踪进程运行所需的所有状态信息。这种状态,就是上下文。

在任何一个时刻,操作系统都只能执行一个进程代码,当操作系统决定把控制权从当前进程转移到某个新进程时,就会进行上下文切换,即保存当前进程的上下文,恢复新进程的上下文,然后将控制权传递到新进程,新进程就会从它上次停止的地方开始。


不同点:


执行流的调度者不同,进程是内核调度,而协程是在用户态调度,也就是说进程的上下文是在内核态保存恢复的,而协程是在用户态保存恢复的,很显然用户态的代价更低

进程会被强占,而协程不会,也就是说协程如果不主动让出CPU,那么其他的协程,就没有执行的机会。

对内存的占用不同,实际上协程可以只需要4K的栈就足够了,而进程占用的内存要大的多

从操作系统的角度讲,多协程的程序是单进程,单协程

1.2 线程和协程

既然我们上面也说了,协程也被称为微线程,下面对比一下协程和线程:


线程之间需要上下文切换成本相对协程来说是比较高的,尤其在开启线程较多时,但协程的切换成本非常低。

同样的线程的切换更多的是靠操作系统来控制,而协程的执行由我们自己控制。

协程只是在单一的线程里不同的协程之间切换,其实和线程很像,线程是在一个进程下,不同的线程之间做切换,这也可能是协程称为微线程的原因吧。

2. 简介

Gevent 模块是一种基于协程的Python网络库,它用到Greenlet提供的,封装了libevent事件循环的高层同步API。它让开发者在不改变编程习惯的同时,用同步的方式写异步I/O的代码。

2.1 greenlets

如果想了解gevent的调度流程,最重要的是对greenlet有基本的了解。下面总结一些个人认为比较重要的点:


每一个greenlet.greenlet实例都有一个parent(可指定,默认为创生新的greenlet.greenlet所在环境),当greenlet.greenlet实例执行完逻辑正常结束、或者抛出异常结束时,执行逻辑切回到其parent

可以继承greenlet.greenlet,子类需要实现run方法,当调用greenlet.switch方法时会调用到这个run方法

在gevent中,有两个类继承了greenlet.greenlet,分别是gevent.hub.Hub和gevent.greenlet.Greenlet。后文中,如果是greenlet.greenlet这种写法,那么指的是原生的类库greentlet,如果是greenlet(或者Greenlet)那么指gevent封装后的greenlet。


gevent中的主要模式, 它是以C扩展模块形式接入Python的轻量级协程。 全部运行在主程序操作系统进程的内部,但它们被程序员协作式地调度。


在任何时刻,只有一个协程在运行。


区别于multiprocessing、threading等提供真正并行构造的库, 这些库轮转使用操作系统调度的进程和线程,是真正的并行。

3. 特点

基于libev的快速事件循环(Linux上epoll,FreeBSD上kqueue)。
基于greenlet的轻量级执行单元。
API的概念和Python标准库一致(如事件,队列)。
可以配合socket,ssl模块使用。
能够使用标准库和第三方模块创建标准的阻塞套接字(gevent.monkey)。
默认通过线程池进行DNS查询,也可通过c-are(通过GEVENT_RESOLVER=ares环境变量开启)。
TCP/UDP/HTTP服务器
子进程支持(通过gevent.subprocess)
线程池

4. 安装

安装和依赖

依赖于greenlet library

支持python 2.6+ 、3.3+

pip install gevent

5. 示例

5.1 用greenlet执行一个函数

#coding:utf-8
import time
from  greenlet import greenlet
def eat():
    print('魔降风云变 is eating')
    time.sleep(0.5)
    print('魔降风云变 finished eat')
def sleep():
    print('小马过河 is sleeping')
    time.sleep(0.5)
    print('小马过河 finished sleep')
g1 = greenlet(eat)
g1.switch()

--------------结果:

魔降风云变 is eating
魔降风云变 finished eat

在一个任务函数中切换到另一个任务函数去执行,然后没有再切换回来

#coding:utf-8
import time
from  greenlet import greenlet
def eat():
    print('魔降风云变 is eating')
    g2.switch()
    time.sleep(0.5)
    print('魔降风云变 finished eat')
def sleep():
    print('小马过河 is sleeping')
    time.sleep(0.5)
    print('小马过河 finished sleep')
g1 = greenlet(eat)
g2 = greenlet(sleep)
g1.switch()

--------------结果:

魔降风云变 is eating
小马过河 is sleeping
小马过河 finished sleep

一个任务中切换到另一个任务,另一个任务执行完了再执行切换回到这个任务执行。实现两个任务间切换并都执行结束

#coding:utf-8
import time
from  greenlet import greenlet
def eat():
    print('魔降风云变 is eating')
    g2.switch()
    time.sleep(0.5)
    print('魔降风云变 finished eat')
def sleep():
    print('小马过河 is sleeping')
    time.sleep(0.5)
    print('小马过河 finished sleep')
    g1.switch()
g1 = greenlet(eat)
g2 = greenlet(sleep)
g1.switch()

------------结果:

魔降风云变 is eating
小马过河 is sleeping
小马过河 finished sleep
魔降风云变 finished eat

5.2 创建协程任务

``python
#coding:utf-8
import time
import gevent
def eat():
    print('魔降风云变 is eating')
    time.sleep(1)
    print('魔降风云变  finished eat')
def sleep():
    print('小马过河 is sleeping')
    time.sleep(1)
    print('小马过河 finished sleep')
g1 = gevent.spawn(eat)  # 创造一个协程任务

-----------结果:没有输出

协程遇到阻塞才切换,这里代码从上到下执行结束,没有遇到阻塞

import time
import gevent
def eat():
    print('魔降风云变 is eating')
    time.sleep(1)
    print('魔降风云变  finished eat')
def sleep():
    print('小马过河 is sleeping')
    time.sleep(1)
    print('小马过河 finished sleep')
g1 = gevent.spawn(eat)  # 创造一个协程任务
gevent.sleep(2) #加个gevent.sleep(2)就切换到eat执行里面的代码了

---------结果:

魔降风云变 is eating
魔降风云变  finished eat

#加个gevent.sleep(2)就切换到eat执行里面的代码了。eat中间time.sleep(1)照样睡。

5.3 同步和异步执行

两个子任务之间的 切换也就是上下文切换。

创建Greenlets,gevent对Greenlet初始化提供了一些封装.

第一个

import gevent
def test1():
  print 12
  gevent.sleep(0)
  print 34
def test2():
  print 56
  gevent.sleep(0)
  print 78
gevent.joinall([
  gevent.spawn(test1),
  gevent.spawn(test2),
])
$ python gevent2.py
12
56
34
78

第二个

import gevent
from gevent import Greenlet
def foo(message, n):
    gevent.sleep(n)
    print(message)
    thread1 = Greenlet.spawn(foo, "Hello", 1)
    thread2 = gevent.spawn(foo, "I live!", 2)
    thread3 = gevent.spawn(lambda x: (x+1), 2)
    threads = [thread1, thread2, thread3]
    gevent.joinall(threads)

第二个

$ python gevent3.py
Hello
I live!

5.4 同步vs异步

import gevent
import random
def task(pid):
    gevent.sleep(random.randint(0,2)*0.001)
    print('Task %s done' % pid)
def synchronous():
    for i in xrange(5):
        task(i)
def asynchronous():
    threads = [gevent.spawn(task, i) for i in xrange(5)]
    gevent.joinall(threads)
    print('Synchronous:')
    synchronous()
    print('Asynchronous:')
    asynchronous()
$ python gevent3.py
Synchronous:
Task 0 done
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Asynchronous:
Task 2 done
Task 0 done
Task 1 done
Task 3 done
Task 4 done

参考:

相关文章
|
3天前
|
数据挖掘 API 数据安全/隐私保护
python请求模块requests如何添加代理ip
python请求模块requests如何添加代理ip
|
4天前
|
测试技术 Python
Python 有趣的模块之pynupt——通过pynput控制鼠标和键盘
Python 有趣的模块之pynupt——通过pynput控制鼠标和键盘
|
4天前
|
Serverless 开发者 Python
《Python 简易速速上手小册》第3章:Python 的函数和模块(2024 最新版)
《Python 简易速速上手小册》第3章:Python 的函数和模块(2024 最新版)
37 1
|
5天前
|
调度 Python
Python多线程、多进程与协程面试题解析
【4月更文挑战第14天】Python并发编程涉及多线程、多进程和协程。面试中,对这些概念的理解和应用是评估候选人的重要标准。本文介绍了它们的基础知识、常见问题和应对策略。多线程在同一进程中并发执行,多进程通过进程间通信实现并发,协程则使用`asyncio`进行轻量级线程控制。面试常遇到的问题包括并发并行混淆、GIL影响多线程性能、进程间通信不当和协程异步IO理解不清。要掌握并发模型,需明确其适用场景,理解GIL、进程间通信和协程调度机制。
21 0
|
7天前
|
Python
python学习-函数模块,数据结构,字符串和列表(下)
python学习-函数模块,数据结构,字符串和列表
44 0
|
8天前
|
Python
python学习14-模块与包
python学习14-模块与包
|
9天前
|
SQL 关系型数据库 数据库
Python中SQLite数据库操作详解:利用sqlite3模块
【4月更文挑战第13天】在Python编程中,SQLite数据库是一个轻量级的关系型数据库管理系统,它包含在一个单一的文件内,不需要一个单独的服务器进程或操作系统级别的配置。由于其简单易用和高效性,SQLite经常作为应用程序的本地数据库解决方案。Python的内置sqlite3模块提供了与SQLite数据库交互的接口,使得在Python中操作SQLite数据库变得非常容易。
|
1月前
|
并行计算 调度 开发者
深入浅出Python协程:提升你的异步编程效率
在当今快速发展的软件开发领域,异步编程已成为提高程序性能和用户体验的关键技术。Python,作为一门广泛使用的高级编程语言,其协程(Coroutine)功能为开发者提供了强大的异步编程工具。本文将从协程的基本概念入手,通过实例深入浅出地讲解如何在Python中有效利用协程来提升异步编程的效率和可读性。我们将探讨协程的工作原理、与传统多线程/多进程相比的优势,以及如何在实际项目中应用协程来解决复杂的并发问题。通过本文的学习,读者将能够掌握Python协程的核心知识,为构建高效、可维护的异步应用奠定坚实基础。
|
27天前
|
API 数据处理 调度
Python中的异步编程与协程应用
传统的Python编程在处理IO密集型任务时常常面临效率低下的问题,而异步编程和协程技术的引入为解决这一问题提供了有效的途径。本文将介绍Python中异步编程的基本概念,深入探讨asyncio库的使用以及协程在实际项目中的应用,旨在帮助开发者更好地理解和运用异步编程技术。
|
1月前
|
调度 Python
python协程—asyncio模块
python协程—asyncio模块
24 0