python线程、进程和协程详解

Python 线程、进程和协程详解

在 Python 中,程序运行的实体可以分为线程、进程和协程。它们各自有着不同的特点和适用范围。

线程

什么是线程?

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中真正执行的实体。

Python 的线程是操作系统的原生线程,由操作系统调度。Python 使用 threading 模块来创建线程。

如何创建线程?

可以使用 threading.Thread 类创建线程,例如:

import threading

def task():
    print("This is a task.")

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

上述代码使用 threading.Thread 类创建了一个新的线程 t,并把 task 函数作为线程的执行目标。t.start() 表示启动线程。

线程的状态

线程的状态包括:

  • 新建状态(NEW):线程对象已经创建,但是还没有调用 start() 方法。
  • 就绪状态(READY):线程对象已经调用 start() 方法,等待系统分配线程资源。
  • 运行状态(RUNNING):线程处于可执行状态并且正在运行中。
  • 阻塞状态(BLOCKED):线程因为某些原因暂停了自己的执行,例如等待 I/O 操作完成。
  • 终止状态(TERMINATED):线程执行完成,退出了。

线程同步

多个线程有时需要协调它们的执行顺序,避免出现冲突和不一致的结果。这就需要线程同步。Python 提供了多种线程同步工具,例如 LockRLockSemaphore 等。

以下是一个使用 Lock 实现线程同步的示例:

import threading

cnt = 0
lock = threading.Lock()

def increase():
    global cnt
    lock.acquire()
    cnt += 1
    lock.release()

threads = []
for i in range(10):
    t = threading.Thread(target=increase)
    threads.append(t)

for t in threads:
    t.start()

for t in threads:
    t.join()

print(cnt)

上述代码定义了一个共享变量 cnt,并使用 Lock 同步多个线程对 cnt 的修改。如果不加同步,可能会出现多个线程同时修改 cnt,导致结果出错。加上同步之后,每次只有一个线程能够获得锁,保证了对 cnt 同时只有一个线程在修改。

进程

什么是进程?

进程是操作系统中执行的一个程序。在 Unix 和 Linux 系统中,每个进程都有一个唯一的进程标识符(PID)。

Python 使用 multiprocessing 模块来创建进程。

如何创建进程?

可以使用 multiprocessing.Process 类创建进程,例如:

import multiprocessing

def task():
    print("This is a task.")

p = multiprocessing.Process(target=task)
p.start()

上述代码使用 multiprocessing.Process 类创建了一个新的进程 p,并把 task 函数作为进程的执行目标。p.start() 表示启动进程。

进程间通信

不同进程之间无法直接共享内存,需要使用进程间通信(IPC)的方式来交换数据和消息。Python 提供了多种进程间通信方式,例如 QueuePipeManager 等。

以下是一个使用 Queue 实现进程间通信的示例:

import multiprocessing

def worker(q):
    while True:
        item = q.get()
        if item is None:
            break
        print(item)

q = multiprocessing.Queue()
p = multiprocessing.Process(target=worker, args=(q,))
p.start()

for i in range(10):
    q.put(i)

q.put(None)
p.join()

上述代码定义了一个 worker 函数来处理 Queue 中的数据,主进程向 Queue 中写入 10 个整数并以 None 结束。worker 进程不断从 Queue 中取出数据并打印,直到碰到 None 为止。

进程池

进程池是一种并发编程的方式,它可以在执行任务时,自动帮助开发者维护一定数目的进程数量,在某些场景下可以提升程序的执行效率。

Python 提供了 multiprocessing.Pool 模块来实现进程池。

以下是一个使用进程池实现多进程并发下载的示例:

import requests
from multiprocessing.pool import Pool

urls = [
    "https://www.python.org",
    "https://www.github.com",
    "https://www.baidu.com",
    "https://www.bing.com",
]

def download(url):
    resp = requests.get(url)
    print(url, len(resp.content))

pool = Pool(processes=4)
pool.map(download, urls)
pool.close()
pool.join()

上述代码定义了一个 download 函数来下载指定 URL 的内容,并使用进程池同时下载多个 URL。processes=4 表示创建一个拥有 4 个进程的进程池。map 方法接受一个列表作为参数,表示要执行的任务列表,自动分配给进程池中的进程进行执行。

协程

什么是协程?

协程是一种用户态(用户级)的线程,不需要操作系统进行线程调度,可以由应用程序主动挂起和恢复。与进程、线程相比,协程更加轻量级,能够同时执行许多任务。

Python 使用 asyncio 模块来支持协程。

如何创建协程?

可以使用 async def 关键字定义协程函数,例如:

import asyncio

async def task():
    print("This is a coroutine task.")

loop = asyncio.get_event_loop()
loop.run_until_complete(task())
loop.close()

上述代码定义了一个 task 协程函数,并使用 loop.run_until_complete 方法来运行它。

协程间通信

与线程类似,协程之间也需要通信来协调它们之间的执行。Python 提供了 asyncio.Queue 类来实现协程间的通信。

以下是一个使用 asyncio.Queue 实现协程间通信的示例:

import asyncio

async def producer(q):
    for i in range(10):
        await q.put(i)
    await q.put(None)

async def consumer(q):
    while True:
        item = await q.get()
        if item is None:
            break
        print(item)

q = asyncio.Queue()
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(
    producer(q),
    consumer(q),
))
loop.close()

上述代码定义了一个 producer 协程函数和一个 consumer 协程函数,producer 协程向 Queue 中写入 10 个整数并以 None 结束,consumer 协程不断从 Queue 中取出数据并打印,直到碰到 None 为止。

协程池

协程池是一种更加高级的协程管理方式,其可以同时管理多个协程,根据任务情况决定是否创建新协程,提升协程的效率。

Python 提供了 asyncio 模块的 ThreadPoolExecutorProcessPoolExecutor 类来实现协程池。

以下是一个使用协程池同时下载多个 URL 的示例:

import asyncio
import aiohttp

urls = [
    "https://www.python.org",
    "https://www.github.com",
    "https://www.baidu.com",
    "https://www.bing.com",
]

async def download(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            print(url, len(await resp.read()))

async def main():
    tasks = [asyncio.ensure_future(download(url)) for url in urls]
    await asyncio.gather(*tasks)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

上述代码定义了一个 download 协程函数,使用 aiohttp 库下载指定 URL 的内容。通过创建多个 asyncio.ensure_future 对象并使用 asyncio.gather 方法同时运行多个协程。线程池和进程池的实现与之类似,只需要将 ThreadPoolExecutorProcessPoolExecutor 作为事件循环的参数即可。

总的来说,Python 中的线程、进程、协程的使用方式多种多样,开发者可以根据自己的业务需求来选择适合的方式来实现多任务并发。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python线程、进程和协程详解 - Python技术站

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

相关文章

  • 13个最常用的Python深度学习库介绍

    13个最常用的Python深度学习库介绍 本文将介绍13个最常用的Python深度学习库,包括TensorFlow、PyTorch、Keras、CNTK、Theano、MXNet、Caffe、Chainer、Lasagne、PaddlePaddle、Gluon、Torch和DeepLearning4J。我们将介绍每个库的基本原理、特点和使用方法,并提供两个示…

    python 2023年5月14日
    00
  • Python:format格式化字符串详解

    Python: format格式化字符串详解 一、什么是格式化字符串? 格式化字符串是指,在定义字符串时,在字符串内部插入变量,使其能够根据不同的变量在输出时有不同的格式。 例如,在Python中,可以通过print()函数输出字符串,如: print("Hello, Python!") 输出结果为: Hello, Python! 但是,…

    python 2023年6月5日
    00
  • 对python多线程中Lock()与RLock()锁详解

    题目:对Python多线程中 Lock() 与 RLock() 锁详解的攻略 1. 简介 在Python中,多线程编程时可能会造成线程之间的互斥问题,为了解决这个问题,Python内置了两种锁机制:Lock() 和 RLock()锁。这两种锁机制的功能类似,但是在使用场景和处理细节上略有不同。接下来我将分别介绍它们的详细用法。 2. Lock() 锁 2.1…

    python 2023年5月18日
    00
  • python import模块时有错误红线的原因

    当我们在Python中导入模块时,有时会出现错误红线,这通常是由于以下原因之一引起的: 模块不存在或路径不正确 模块中存在语法错误。 模块中存在行时错误。 以下是解决这些问题方法: 模块不存在或路径不正确 当我们导入模块时,如果模块不存在或路径不正确,就会出现错误红线。是解决这个问题的方法: 检查模块存在。 检查模块路径是否正确。 例如,我们可以使用以下代码…

    python 2023年5月13日
    00
  • python中使用百度音乐搜索的api下载指定歌曲的lrc歌词

    要在Python中使用百度音乐搜索API下载指定歌曲的LRC歌词,可以按照以下步骤进行: 1. 准备工作 首先,需要在百度开发者官网中,申请一个百度音乐开发者账号,然后创建一个音乐应用,以获取调用百度音乐API所需的access_token。 2. 搜素指定歌曲 在获取了access_token之后,就可以使用百度音乐API进行歌曲搜索了。搜索API的地址为…

    python 2023年6月3日
    00
  • python中模块导入模式详解

    关于“Python中模块导入模式详解”的攻略,可以从以下几个方面进行详细讲解: 1. 模块的基本概念 在Python中,模块是一个包含Python定义和语句的文件。模块可以被其他程序导入和使用。使用模块的好处是在不同的程序之间共享代码,同时可以更好地组织和维护代码。 2. 模块导入的方式 Python中有多种导入模块的方式: a. import语句 impo…

    python 2023年6月2日
    00
  • python自动导入包的实现

    自动导入包是Python中十分常见的功能,不必需要手动导入每一个模块,而是可以通过程序自动地扫描指定目录下的模块并进行自动导入。以下是Python自动导入包的实现攻略: 1. 创建子包和模块 要实现自动导入一个包,首先需要通过创建子包和模块来组织代码。创建一个模块时,通常是一个以.py为扩展名的文件。子包是一个包含其他模块的目录。目录的名称表示包的名称,而其…

    python 2023年5月19日
    00
  • Python unittest 自动识别并执行测试用例方式

    Python unittest是Python自带的一个单元测试框架,可以帮助我们设计和执行单元测试。unittest提供了丰富的断言函数和测试用例的管理方法。其中,unittest自动识别并执行测试用例的方式有两种: 1.自动发现测试用例 unittest可以自动发现所有以“test_”开头的测试用例,并自动执行它们。具体步骤如下: 在测试文件中定义一个或多…

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