python线程、进程和协程详解

yizhihongxing

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日

相关文章

  • Python实现自动整理文件的示例代码

    下面是Python实现自动整理文件的示例代码的完整攻略,包含以下步骤: 创建项目目录 首先,我们需要在本地创建一个项目目录,作为我们整理文件的基础。可以选择在桌面或其他文件夹中创建,以下是示例目录结构: automate-files/ ├── organize.py ├── desktop/ │ ├── documents/ │ ├── images/ │ …

    python 2023年5月19日
    00
  • 基于Python实现简单的定时器详解

    基于Python实现简单的定时器详解 概述 定时器是一种常用的编程工具,在某段时间间隔后执行特定的操作,常用于多线程、网络编程、定时任务等场景。Python标准库提供了多种方式实现定时器,如time.sleep()、threading.Timer()、sched.scheduler()等,本文将介绍基于threading.Timer()实现简单定时器的实现方…

    python 2023年5月19日
    00
  • Python中几种导入模块的方式总结

    下面我将给你详细讲解Python中几种导入模块的方式总结。 在Python中,我们可以使用import语句来导入一个模块。有如下几种导入模块的方式: 1. 直接导入模块(import module_name) 这种方式是最简单的导入方式,直接使用import语句后,加上要导入的模块即可。示例代码如下: # 导入 math 模块 import math # 使…

    python 2023年6月3日
    00
  • plt.subplot()参数及使用介绍

    下面是“plt.subplot()参数及使用介绍”的完整攻略。 plt.subplot()是什么 plt.subplot() 是 matplotlib 库中的一个子图绘制函数,用于将一个画布分成多个子区域画不同的图形。它常用于多图绘制,支持绘制基础图表,如线图、散点图、柱状图等。 plt.subplot()参数介绍 plt.subplot() 函数常用于分割…

    python 2023年5月18日
    00
  • python基础知识之try…except…的详细用法实例

    这里是“python基础知识之try…except”的详细用法实例攻略。 标题 一、try…except…语句的作用 try…except…语句用于捕获可能出现异常的代码块。当程序运行时如果发生了异常,程序将会停止运行,并输出异常信息。为了使程序更加健壮,我们可以使用try…except…语句来处理异常,使得即使代码出现异常,也可…

    python 2023年5月13日
    00
  • python自动统计zabbix系统监控覆盖率的示例代码

    下面我将为您详细讲解如何实现Python自动统计Zabbix系统监控覆盖率的示例代码攻略。 1. 准备工作 在开始实现之前,需要进行以下准备工作: 搭建Zabbix监控系统并添加监控项、触发器等; 安装Python,并搭建Python Web框架,如Django; 安装Python库zabbix-api(可通过 pip install zabbix-api …

    python 2023年6月3日
    00
  • python 遗传算法求函数极值的实现代码

    Python遗传算法求函数极值的实现代码 遗传算法是一种常用的优化算法,它可以用于求解函数极值。在本文中,我们将介绍如何使用Python实现遗传算法求函数极值。我们分为以下几个步骤: 导入必要的库 定义适应度函数 定义遗传算法类 示例说明 步骤1:导入必要的库 实现遗传算之前,我们需要导入必要的库。在这个例子中,我们将使用numpy库进行数值计算,rando…

    python 2023年5月14日
    00
  • Python获取网段内ping通IP的方法

    下面是 “Python获取网段内ping通IP的方法” 的完整攻略。 一、背景说明 在进行网络相关的测试或操作时,我们有时需要获取当前局域网中哪些主机是可以ping通的,这在排查网络故障、寻找设备等情况下是非常有用的。而Python是一门功能强大的编程语言,可以方便地进行网络测试,下面我们来看一下如何使用Python获取指定网段内ping通的IP地址。 二、…

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