Python从使用线程到使用async/await的深入讲解

Python从使用线程到使用async/await的深入讲解

1. 线程

1.1 什么是线程?

线程是程序执行流的最小单元,是进程的一个执行单元。线程通过共享运行时环境,可以提高程序的并发性,线程有轻量级、及时性等特点。

1.2 Python的线程模块

Python的标准库threading提供了线程相关的模块,使用起来非常简单。

import threading

def worker():
    print('Thread %s is working' % threading.current_thread().getName())

t = threading.Thread(target=worker)
t.start()

上述代码中,使用threading.Thread类创建线程对象,使用start方法启动线程,使用current_thread方法获取当前线程对象,使用getName方法获取线程名。

1.3 线程的并发问题

虽然Python的线程机制非常易用,但是Python的线程是基于操作系统底层线程的,而不是真正的并发线程。因为Python的Global Interpreter Lock (GIL)机制,同一时刻只能有一个线程在执行Python代码,其他线程只能在等待GIL。所以使用线程并不能真正充分利用多核CPU,也无法真正实现多线程并发。因此,使用线程可能带来线程切换的开销而降低程序性能。

2. 协程

2.1 什么是协程?

协程是一种用户态的轻量级线程,也称为纤程 (Fiber),协程可以看作特殊的迭代器,可以由程序员控制运行状态,支持用户态调度,无线程切换开销。

2.2 Python的协程模块

Python 3.5开始加入async/await语法实现原生协程。使用协程需要用到Python的asyncio模块。

下面是一个使用async/await语法的协程示例:

import asyncio

async def worker():
    print('Coroutine is working')
    await asyncio.sleep(1)
    print('Coroutine is finished')

loop = asyncio.get_event_loop()
loop.run_until_complete(worker())

上述代码中,使用asyncawait定义协程,使用asyncio.sleep模拟协程执行任务,使用get_event_loop方法获取事件循环对象,使用run_until_complete方法运行协程。

2.3 协程和线程的区别

线程和协程都是并发机制,但是线程是基于操作系统底层线程的,因此他们的并发模型在底层上有很大的区别。协程通过用户态调度,对于大量I/O密集型操作的场景非常适用,但是对于CPU密集型操作的场景则不一定有优势,因为无法利用多核CPU。

3. 示例说明

3.1 线程示例

下面是一个使用线程池的示例,实现并发下载多张图片:

import requests
import threading
from concurrent.futures import ThreadPoolExecutor

def download(url, filename):
    print('Thread %s is downloading image: %s' % (threading.current_thread().getName(), url))
    resp = requests.get(url)
    with open(filename, 'wb') as f:
        f.write(resp.content)

urls = ['https://picsum.photos/200/200/?image=%d' % i for i in range(10)]
pool = ThreadPoolExecutor(max_workers=5)
for i, url in enumerate(urls):
    filename = 'image_%d.jpg' % i
    pool.submit(download, url, filename)

在该示例中,使用requests发送网络请求下载多张图片,使用ThreadPoolExecutor创建线程池,并通过submit方法向线程池中提交任务。由于线程是基于操作系统底层线程的,所以程序在执行过程中会有线程切换的开销。

3.2 协程示例

下面是一个使用协程的示例,实现并发下载多张图片:

import aiohttp
import asyncio

async def download(url, filename):
    print('Coroutine is downloading image: %s' % url)
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            with open(filename, 'wb') as f:
                f.write(await resp.content.read())

urls = ['https://picsum.photos/200/200/?image=%d' % i for i in range(10)]
tasks = [download(url, 'image_%d.jpg' % i) for i, url in enumerate(urls)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*tasks))

在该示例中,使用aiohttp发送异步网络请求下载多张图片,使用asyncio异步执行协程任务。由于协程是用户态调度,不需要线程切换的开销,可以提高程序的性能。

4. 总结

线程和协程都是并发编程的重要方式,但是在线程和协程之间需要根据实际需求进行选择。在大量I/O密集型操作的场景下,协程可以取得很好的效果,而在大量CPU密集型操作的场景下,则需要考虑使用多进程或大规模并行计算。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python从使用线程到使用async/await的深入讲解 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • python 列表套json字典根据相同的key筛选数据

    当Python列表中嵌套着多个JSON字典,我们要从中筛选出与某个key相同的数据时,可以通过以下步骤操作: 使用json库中的loads()函数将JSON字符串转换为Python字典 遍历Python列表,逐个字典查找目标key并匹配 如果匹配成功,则保存该字典到一个新的列表 下面,我们将通过两个示例详细讲述这个过程。 示例一 假设我们有如下一个Pytho…

    python 2023年6月3日
    00
  • Python自动化办公之生成PDF报告详解

    Python自动化办公之生成PDF报告详解 简介 本攻略将详细介绍如何使用Python语言自动化生成PDF报告。我们将使用Python中的reportlab库,Pillow库,以及Pandas库,通过数据处理和图表可视化来生成具有分析性质的PDF报告。 准备工作 在使用reportlab库来生成PDF文件之前,需要进行以下准备工作: 1.安装reportla…

    python 2023年6月5日
    00
  • Python 3.7 数据类中的类继承

    【问题标题】:Class inheritance in Python 3.7 dataclassesPython 3.7 数据类中的类继承 【发布时间】:2023-04-05 07:29:02 【问题描述】: 我目前正在尝试 Python 3.7 中引入的新数据类结构。我目前坚持尝试对父类进行一些继承。看起来参数的顺序被我当前的方法搞砸了,因此子类中的 bo…

    Python开发 2023年4月5日
    00
  • python dict乱码如何解决

    当在Python中处理字典时,如果出现了乱码,一般是由于编码问题引起的。在处理字典时,推荐将字符串转成Unicode格式,这样就不会出现编码问题。 下面是解决Python dict乱码的两种示例: 示例一:使用json模块解析乱码 有时候,我们可能需要将Python dict转换成json格式进行传输,而json格式不支持某些字符集,因此,在转换时可能会出现…

    python 2023年5月20日
    00
  • 实例介绍Python中整型

    实例介绍Python中整型 Python中整型(int)是一种基本数据类型,表示整数。Python的整数可以是任意大的,而不会出现溢出或符号问题。在Python中,整型是不可变类型,即值一旦确定就不可更改。本文将介绍Python中整型的各种使用方法和示例。 创建整型对象 在Python中,我们可以使用以下方式创建整型对象: # 10进制表示 a = 42 #…

    python 2023年6月5日
    00
  • 更改 Python 脚本的 DNS 服务器

    【问题标题】:Changing DNS server for Python script更改 Python 脚本的 DNS 服务器 【发布时间】:2023-04-05 11:42:01 【问题描述】: 我正在编写一个脚本,该脚本将在我大学的服务器上运行。该脚本的目的是检查网站并记录其 HTTP 状态代码和 IP 地址。这通常可以正常工作,但我遇到了一个我很难…

    Python开发 2023年4月5日
    00
  • Python使用迭代器打印螺旋矩阵的思路及代码示例

    当需要打印螺旋矩阵时,我们可以使用迭代器的方法逐行或逐列进行输出。下面是Python使用迭代器打印螺旋矩阵的思路及代码示例。 思路 定义一个迭代器函数,输入参数为二维数组matrix。 定义一个迭代器变量direction,表示遍历方向(向右、向下、向左、向上)。 定义四个变量r1、r2、c1、c2,表示矩阵四角的行与列。 在迭代器函数里,循环遍历矩阵,输出…

    python 2023年6月3日
    00
  • python 双循环遍历list 变量判断代码

    以下是“Python双循环遍历list变量判断代码”的完整攻略。 1. 双循环遍历list变量 在Python中,可以使用双循环遍历list变量,以实现对list中元素的判断。示例如下: my_list = [1, 2, 3, 4, 5, 6] for i in my_list: for j in my_list: if i + j == 7: print(…

    python 2023年5月13日
    00
合作推广
合作推广
分享本页
返回顶部