Python并发学习

2023-05-16

Python并发

  • 1、多进程(和多线程的方式类似)
  • 2、多线程(2种编写方式)
    • 2.1 submit方式
    • 2.2 map方式
  • 3、异步(协程)
    • 3.1 调用方式
      • 3.1.1 在协程函数里去调用协程
      • 3.1.2 在非协程函数里去调用协程
    • 3.2 协程睡眠
    • 3.3 验证某一个函数是否为协程函数
    • 3.4 同时运行多个协程
    • 3.5 协程关闭
    • 3.6 协程其他
    • 3、2
    • 3、3

1、多进程(和多线程的方式类似)




2、多线程(2种编写方式)

2.1 submit方式

futures={pool.submit(get_html_from_url,url): url for url in urls}
for future in concurrent.futures.as_completed(futures):
    data=future.result()

2.2 map方式

with ThreadPoolExecutor(max_workers=10)as pool:
    for data in pool.map(spider.get_html_from_url_by_fpclient,urls):




3、异步(协程)

Python3版本引入了async/await特性,其特点是:当执行过程中遇到 IO 请求的时候,可以将CPU资源出让,运行其他的任务;待IO完成之后,继续执行之前的任务。协程切换与线程切换比较类似,但协程切换更轻,不需要操作系统参与(没有栈切换操作,也没有用户态与内核态切换)。

3.1 调用方式

3.1.1 在协程函数里去调用协程

import asyncio


async def func_1():
# 第一步:定义一个协程函数
    print("start")
    await asyncio.sleep(1)
    print("end")

async def func_2(): 
# 第二步:在函数内部调用协程函数,自身也必须定义为协程
# func_1()调用产生了一个协程对象,通过await来执行这个协程。如果不加await,
# 直接以func_1()方式调用,则func_1中代码并不会执行。
    await func_1()  

loop = asyncio.get_event_loop()
# 第二步:创建事件大循环
"""Run the event loop until a Future is done."""
loop_result = loop.run_until_complete(func_1())  # 阻塞调用,直到协程运行结束才返回。

3.1.2 在非协程函数里去调用协程

一般情况下,无法在一个非协程函数中阻塞地调用另一个协程。
但你可以通过**asyncio.ensure_future()**来异步执行这个协程:

import asyncio


async def func_1():
# 第一步:定义一个协程函数
    print("start")
    await asyncio.sleep(1)
    print("end")

def func_2(): 
asyncio.ensure_future(fun_1()) 
# 这里fun_1()将会在某个时间执行,具体执行顺序未知    
# 这里是阻塞执行fun_1(),但这种调用,只能在event loop进入循环之前调用(loop.run_forever()),    
# 否则会抛异常
    asyncio.get_event_loop().run_until_complete(fun_1) 
    print("fun_1() is executed!")

3.2 协程睡眠

协程函数在执行中会占用本线程的全部CPU时间,除非遇到IO切换出去。
因此,如果你在函数中使用 time.sleep(),在多线程中,一个线程进入sleep状态,操作系统会切换到其它线程执行,整个程序仍然是可响应的(除了该线程,它必须等待睡眠状态结束);
而对协程来说,同一loop中的其它协程都不会得到执行,因为这个sleep会占用本线程的全部执行时间,直到协程执行完毕。
如果一个协程确实需要睡眠(比如某种定时任务)但是又不能影响同一线程中的其他协程,必须使用asyncio.sleep()

3.3 验证某一个函数是否为协程函数

print(asyncio.iscoroutinefunction(do_some_work)) # True

3.4 同时运行多个协程

两种方法

# 方法一:
loop.run_until_complete(asyncio.gather(do_some_work(3), do_some_work(5)))


# 方法二:先存成列表,在同时运行
coros = [do_some_work(1), do_some_work(3)]
loop.run_until_complete(asyncio.gather(*coros))


3.5 协程关闭

关闭循环:loop 只要不关闭,就还可以再运行。但是如果关闭了,就不能再运行了。
建议调用 loop.close,以彻底清理 loop 对象防止误用。

3.6 协程其他

异步IO:就是发起一个IO操作(如:网络请求,文件读写等),这些操作一般是比较耗时的,不用等待它结束,可以继续做其他事情,结束时会发来通知。
协程:又称为微线程,在一个线程中执行,执行函数时可以随时中断,由程序(用户)自身控制,执行效率极高,与多线程比较,没有切换线程的开销和多线程锁机制。

# 重要的概念
1.事件循环
管理所有的事件,在整个程序运行过程中不断循环执行并追踪事件发生的顺序将它们放在队列中,空闲时调用相应的事件处理者来处理这些事件。

2.Future
Future对象表示尚未完成的计算,还未完成的结果

3.Task
是Future的子类,作用是在运行某个任务的同时可以并发的运行多个任务。
asyncio.Task用于实现协作式多任务的库,且Task对象不能用户手动实例化,通过下面2个函数创建:
    asyncio.async()
    loop.create_task() 或 asyncio.ensure_future()


run_until_complete():
阻塞调用,直到协程运行结束才返回。参数是future,传入协程对象时内部会自动变为future

asyncio.sleep():
模拟IO操作,这样的休眠不会阻塞事件循环,前面加上await后会把控制权交给主事件循环,在休眠(IO操作)结束后恢复这个协程。
若在协程中需要有延时操作,应该使用 await asyncio.sleep(),而不是使用time.sleep(),因为使用time.sleep()后会释放GIL,阻塞整个主线程,从而阻塞整个事件循环。

3、2

# 创建Task
loop.create_task():

接收一个协程,返回一个asyncio.Task的实例,也是asyncio.Future的实例,毕竟Task是Future的子类。返回值可直接传入run_until_complete()

返回的Task对象可以看到协程的运行情况
"""
import asyncio


async def coroutine_example():
    print("start1")
    await asyncio.sleep(1)
    print('end1')
    return 1


async def coroutine_example2():
    print("start2")
    await asyncio.sleep(1)
    print('end2')
    return 2

loop = asyncio.get_event_loop()

coro = coroutine_example()
coro2 = coroutine_example2()

task = loop.create_task(coro)
task2 = loop.create_task(coro2)
print('运行情况1:', task)
print('运行情况2:', task2)

loop.run_until_complete(task)


print('再看下运行情况1:', task)
print('再看下运行情况2:', task2)

loop.close()



3、3

# -*- encoding: utf-8 -*-
"""ankus 
@Modify Time      @Author    @Version    @Description
------------      -------    --------    -----------
2021/12/3 14:21   xlgui2      1.0         获取协程返回值

有2种方案可以获取返回值。

第1种方案:通过task.result()

可通过调用 task.result() 方法来获取协程的返回值,
但是只有运行完毕后才能获取,若没有运行完毕,result()方法不会阻塞去等待结果,
而是抛出 asyncio.InvalidStateError 错误

第2种方案:通过add_done_callback()回调

"""

import asyncio

##########################################################################
# ## 第1种方案:通过task.result()
"""
async def coroutine_example():
    await asyncio.sleep(1)
    return 1


loop = asyncio.get_event_loop()
coro = coroutine_example()

task = loop.create_task(coro)
print('运行情况:', task)
try:
    print('返回值:', task.result())
except asyncio.InvalidStateError:
    print('task状态未完成,捕获了 InvalidStateError 异常')

loop.run_until_complete(task)
print('再看下运行情况:', task)
print('返回值:', task.result())
loop.close()

"""


##########################################################################

# ##第2种方案:通过add_done_callback()回调

def my_callback(future):
    print('返回值:', future.result())


async def coroutine_example():
    print("start")
    await asyncio.sleep(1)
    print("end")
    return 1


loop = asyncio.get_event_loop()
coro = coroutine_example()
task = loop.create_task(coro)
task.add_done_callback(my_callback)

loop.run_until_complete(task)
loop.close()



# -*- encoding: utf-8 -*-
"""ankus 
@Modify Time      @Author    @Version    @Description
------------      -------    --------    -----------
2021/12/3 14:46   xlgui2      1.0         控制任务
通过asyncio.wait()可以控制多个任务

asyncio.wait()是一个协程,不会阻塞,立即返回,返回的是协程对象。
传入的参数是future或协程构成的可迭代对象。最后将返回值传给run_until_complete()加入事件循环
"""

import asyncio


async def coroutine_example(name):
    print('正在执行name:', name)
    await asyncio.sleep(3)
    print('执行完毕name:', name)


loop = asyncio.get_event_loop()

tasks = [coroutine_example('task_' + str(i)) for i in range(9)]  # 由协程构成的可迭代对象
wait_coro = asyncio.wait(tasks)
loop.run_until_complete(wait_coro)
loop.close()


# -*- encoding: utf-8 -*-
"""
方案1:需要通过loop.create_task()创建task对象,以便后面来获取返回值
方案2:通过回调add_done_callback()来获取返回值
"""

# 下面代码asyncio.wait()中,参数传入的是由future(task)对象构成的可迭代对象


##############################################
# 方案1:需要通过loop.create_task()创建task对象,以便后面来获取返回值
"""
import asyncio


async def coroutine_example(name):
    print('正在执行name:', name)
    await asyncio.sleep(1)
    print('执行完毕name:', name)
    return '返回值:' + name


loop = asyncio.get_event_loop()

tasks = [loop.create_task(coroutine_example('Zarten_' + str(i))) for i in range(3)]
wait_coro = asyncio.wait(tasks)
loop.run_until_complete(wait_coro)

for task in tasks:
    print(task.result())

loop.close()
"""

########################
# 方案2:通过回调add_done_callback()来获取返回值
import asyncio


def my_callback(future):
    print('返回值:', future.result())


async def coroutine_example(name):
    print('正在执行name:', name)
    await asyncio.sleep(1)
    print('执行完毕name:', name)
    return '返回值:' + name


loop = asyncio.get_event_loop()

tasks = []
for i in range(3):
    task = loop.create_task(coroutine_example('Zarten_' + str(i)))
    task.add_done_callback(my_callback)
    tasks.append(task)

wait_coro = asyncio.wait(tasks)
loop.run_until_complete(wait_coro)

loop.close()





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python并发学习 的相关文章

随机推荐

  • Linux下gitee的使用—— 一看就懂得操作

    在做基于ds18b20温度监控的项目开始时 xff0c 就一直在使用git仓库 xff0c 一直没有写过博客 xff0c 基于今天家里没事 xff0c 刚好可以写一下git版本控制的使用 xff01 废话不多说 xff0c 上教程 xff0
  • 文献阅读2:Deep Video Super-Resolution Network

    Deep Video Super Resolution Network Using Dynamic Upsampling Filters Without Explicit Motion Compensation 隐式运动补偿的动态上采样滤波
  • 形参和实参

    形参和实参的区别 形参出现在函数定义中 xff0c 在整个函数体内都可以使用 xff0c 离开该函数则不能使用 实参出现在主调函数中 xff0c 进入被调函数后 xff0c 实参变量也不能使用 形参和实参的功能是作数据传送 发生函数调用时
  • centos 连接windows远程桌面方法

    目录 1 下载并安装软件nux dextop release rpm 2 安装rdesktop软件 3 远程windows桌面 4 rdesktop退出全屏模式 1 下载并安装软件nux dextop release rpm wget ht
  • Winpcap教程(高级应用)

    循序渐进学习使用WINPCAP xff08 五 xff09 WinPcap或libpca最强大的特点之一就是数据流的过滤引擎 它提供一种高效的方法来只捕获网络数据流的某些数据而且常常和系统的捕获机制相集成 过滤数据的函数是pcap comp
  • linux/ubuntu取消sudo输入密码的办法

    Linux Ubuntu sudo不用输入密码的方法 通常我们并不以root身份登录 xff0c 但是当我们执行某些命令 command 时需要用到root权限 xff0c 我们通常都是用 34 sudo command 34 来执行com
  • verilog通过中+:与-:解决变量内固定长度数据位的动态选取

    在FPGA设计过程 xff0c 尤其是算法实现时hi xff0c 有时往往需要选取某个变量的动态范围地址 xff0c 而verilog中常规的向量标识方法a MSB LSB 往往会发生错误 xff0c 在此可借用a BASE WIDTH 的
  • IDEA配置Hadoop插件

    一 安装插件 1 1搜索的方式安装 xff1a setting中找到plugins插件 xff0c 然后搜索big Data 如下图 xff1a 如果找不到可以修改几个配置试一下 xff1a 如果还是不行 xff0c 你可以在cmd里面 p
  • linux的进程突然没有了

    这几天在linux服务器上跑实验 xff0c 进程占用的空间比较大 xff0c 而且占用的时间也比较长 xff0c 有时候会发现进程突然没有了 这个时候去翻了翻系统的内核日志 xff0c var log 路径下会有一个kern log的日志
  • IDEA建hadoop项目

    一 新建项目project 选择maven xff1b 填写maven的坐标 xff0c groupId xff0c artifactId xff0c 以及 version xff0c 其中groupId是公司域名的反写 xff0c 而ar
  • OpenWRT路由器-中继模式下无线接入

    本文主要介绍刷入了OpenWRT系统的路由器如何作为二级路由器 xff0c 通过wifi接入上一级路由以及发出wifi供本局域网下的设备连接 二级路由器可以增强现有的信号 现在的路由器一般都是双频路由器 xff0c 双频路由器往往是两块网卡
  • XSS(Reflected) 反射型跨站攻击

    今天我学习一下反射型XSS 打开DVWA网站 xff0c 先切换到low级别 xff0c 选择XSS xff08 Reflected xff09 先查看其源代码 xff1a lt php header 34 X XSS Protection
  • Notepad++离线安装NppFTP

    文章目录 第一步 下载第二步 安装第三步 重启Notepad 43 43 后即可使用 第一步 下载 下载地址 xff1a https github com ashkulz NppFTP releases 选择对应版本解压 xff0c x86
  • nested exception is com.microsoft.sqlserver.jdbc.SQLServerException

    今天在写一个数据库语句的时候 xff0c 出现了一个错误 xff0c 话不多说 xff0c 上图 nested exception is com microsoft sqlserver jdbc SQLServerException 仅当使
  • 一文搞懂SpringSecurity,spring-security配置文件详解,史上最全

    一 认证和授权概念 1 在生产环境下我们如果不登录系统是否能对业务进行操作 xff1f 答案显然是否定的 xff0c 要操作这些功能必须首先登录到系统才可以 2 是不是所有用户 xff0c 只要登录成功就都可以操作所有功能呢 xff1f 答
  • map.computeIfAbsent() 详解

    computeIfAbsent 1 首先会判断map中是否有对应的Key xff1b 2 1 如果没有对应的Key xff0c 则会创建一个满足Value类型的数据结构放到Value的位置中 xff1b 2 2 如果有对应的Key xff0
  • SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能

    Spring Security 一 简介 Spring Security是Spring家族中的一个安全管理框架 xff0c 一般Web应用都需要 认证 和 授权 认证 xff1a 验证当前访问系统的是不是本系统的用户 xff0c 并且要确认
  • Java一维数组与二维数组的转换

    准备 现有一个一维数组 xff1a 1 2 3 4 5 6 7 8 9 转为 3 3 的二维数组 xff1a 1 2 3 4 5 6 7 8 9 我们不难看出 xff1a 一维数组第1个元素在数组中为 arr 0 0 一维数组第3个元素在数
  • 采用JSP+Servlet+JDBC完成的一个产品信息管理系统

    项目架构 项目整体采用 xff1a Maven 43 Servlet 43 JSP 43 JDBC 43 bootstrap 43 javascript完成 数据库表设计 t manager 管理员ID 用户名 密码 manager id
  • Python并发学习

    Python并发 1 多进程 和多线程的方式类似 2 多线程 2种编写方式 2 1 submit方式2 2 map方式 3 异步 xff08 协程 xff09 3 1 调用方式3 1 1 在协程函数里去调用协程3 1 2 在非协程函数里去调