Python 并发编程(协程)

目录

    • 一、引入
    • 二、协程介绍
    • 三、Gevent模块
    • 四、同步与异步

一、引入

本章节主要介绍,使用单线程实现并发,即只用一个主线程(很明显可利用CPU只有一个),为此我们需要先回顾下并发的本质:切换+保存状态
Python 并发编程(协程)_第1张图片
ps:在介绍进程理论时,提及进程的三种执行状态,而线程才是执行单位,所以也可以将上图理解为线程的三种状态


二、协程介绍

单线程下并发称为:协程

特点:

  • 单线程下的IO等待降到最低,也就是说协程时,遇到IO会切换执行另一个任务,因此将可以将单线程的能力发挥到最大

缺点:

  • 不能实现并行
  • 单线程下的多个任务一旦遇到IO,整个线程都会阻塞,所有任务都停滞

三、Gevent模块

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在Python内我们使用这个模块,可以让我们的程序运行,达到一个协程的效果

使用方式:

import gevent

g1 = gevent.spawn(func,args,kwargs)
g1 = gevent.spawn(func,args,kwargs)

g1.join() # 等待g1结束
g2.join() # 等待g2结束

# 或者二合一 gevent.joinall([g1,g2])

g1.value # 拿到g1执行func的返回值

遇到IO自动切换任务

import gevent

def test1(name):
    print(f'{name} test1 running')
    gevent.sleep(2)
    print(f'{name} test1 stop')

def test2(name):
    print(f'{name} test2 running')
    gevent.sleep(2)
    print(f'{name} test2 stop')

g1 = gevent.spawn(test1,'jack')
g2 = gevent.spawn(test2,'tom')

gevent.joinall([g1,g2]) # 注意,我们如果不等待任务运行结束,那么遇到阻塞则不会继续运行了

执行结果:

'''
jack test1 running
tom test2 running
jack test1 stop
tom test2 stop
'''

其中gevent.sleep(2)是gevent模块可以识别的IO阻塞

time.sleep(2) 或其它阻塞是gevent模块所不能识别的,所以我们需在文件的开头增加(代码程序运行前)一个方法,来解决这个问题

from gevent import monkey;monkey.patch_all()
# 上面写法等同于:
# from gevent import monkey
# monkey.patch_all()

import gevent
import time

def test1(name):
    print(f'{name} test1 running')
    time.sleep(2)
    print(f'{name} test1 stop')

def test2(name):
    print(f'{name} test2 running')
    time.sleep(2)
    print(f'{name} test2 stop')

g1 = gevent.spawn(test1,'jack')
g2 = gevent.spawn(test2,'tom')

gevent.joinall([g1,g2]) # 注意,我们如果不等待任务运行结束,那么遇到阻塞则不会继续运行了

执行结果

'''
jack test1 running
tom test2 running
jack test1 stop
tom test2 stop
'''

我们可以使用threading.current_thread().getName()来查看它们是由谁来执行的

from gevent import monkey;monkey.patch_all()
import gevent
import time
from threading import current_thread

def test1():
    print(f'{current_thread().getName()} test1 running')
    time.sleep(2)
    print(f'{current_thread().getName()} test1 stop')

def test2():
    print(f'{current_thread().getName()} test2 running')
    time.sleep(2)
    print(f'{current_thread().getName()} test2 stop')

g1 = gevent.spawn(test1)
g2 = gevent.spawn(test2)

gevent.joinall([g1,g2])

执行结果

'''
DummyThread-1 test1 running
DummyThread-2 test2 running
DummyThread-1 test1 stop
DummyThread-2 test2 stop
'''

结果为:DummyThread,表示假线程


四、同步与异步

单线程下,遇到IO时,演示同步与异步的效果

from gevent import monkey;monkey.patch_all()

import gevent
import time

def task():
    time.sleep(2)

start = time.time()
for i in range(5):
    task()
print('同步耗时:%0.2fs' % (time.time() - start)) # 10.2s

def task():
    time.sleep(2)

asy_time = time.time()

g_lis = []
for i in range(5):
    g_lis.append(gevent.spawn(task))

gevent.joinall(g_lis)
print('异步耗时:%0.2fs' % (time.time() - asy_time)) # 2s

# gevent模块,开启一个一个任务等待时,则切换下一个任务,这里每个任务都遇到,所以同时开启,同时一起都在运行,所以结果为2s

技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请点赞 收藏+关注 子夜期待您的关注,谢谢支持!

你可能感兴趣的:(Python进阶,python,并发编程,协程)