多线程 VS 多进程 VS 协程(多线程跟多进程的区别)
citgpt 2024-09-09 02:17 8 浏览 0 评论
多线程、多进程和协程都是实现并发编程的方式,但它们之间有着不同的工作原理和适用场景。
多线程
多线程是指在一个进程中创建多个线程来执行任务。每个线程都拥有独立的执行流程,但它们共享进程的内存空间和其他资源。多线程适合于 I/O 密集型任务,如网络请求、文件读写等。这是因为线程可以避免 I/O 操作的阻塞,从而提高程序的并发性能。但是,多线程也存在一些问题,比如线程间的同步和竞争、GIL 的限制等。
以下是 Python 中使用 threading 模块创建多线程的示例:
import threading
def worker():
"""线程执行的任务"""
print("Worker start")
# do some work
print("Worker end")
# 创建两个线程并启动
thread1 = threading.Thread(target=worker)
thread2 = threading.Thread(target=worker)
thread1.start()
thread2.start()
# 等待线程执行完毕
thread1.join()
thread2.join()
多进程
多进程是指在操作系统中创建多个进程来执行任务。每个进程都拥有独立的地址空间和资源,它们之间需要进行进程间通信来实现数据共享。多进程适合于 CPU 密集型任务,如计算密集型算法、图像处理等。这是因为多进程可以利用多个 CPU 核心进行并行计算,从而提高程序的性能。但是,多进程也存在一些问题,比如进程间的通信和数据同步、进程启动和销毁的开销等。
以下是 Python 中使用 multiprocessing 模块创建多进程的示例:
import multiprocessing
def worker():
"""进程执行的任务"""
print("Worker start")
# do some work
print("Worker end")
# 创建两个进程并启动
process1 = multiprocessing.Process(target=worker)
process2 = multiprocessing.Process(target=worker)
process1.start()
process2.start()
# 等待进程执行完毕
process1.join()
process2.join()
协程
协程是一种轻量级的线程,它通过在单个线程中切换执行上下文来实现并发。协程的优势在于可以避免线程和进程的上下文切换开销,从而提高程序的并发性能。协程适合于 I/O 密集型任务和并发任务,如异步网络请求、协作式任务调度等。但是,协程也存在一些问题,比如需要手动编写异步代码、无法利用多核 CPU 等。
以下是 Python 中使用 asyncio 模块创建协程的示例:
import asyncio
import aiohttp
async def download_image(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
filename = url.split('/')[-1]
with open(filename, 'wb') as f:
while True:
chunk = await response.content.read(1024)
if not chunk:
break
f.write(chunk)
print(f"{filename} downloaded")
async def main():
urls = [
'https://picsum.photos/200/300',
'https://picsum.photos/250/400',
'https://picsum.photos/300/500',
'https://picsum.photos/350/550',
'https://picsum.photos/400/600',
]
tasks = [download_image(url) for url in urls]
await asyncio.gather(*tasks)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
在该示例中,我们使用了 aiohttp 库来实现异步 HTTP 请求。download_image 函数中使用了 async with 语法来打开一个 aiohttp 客户端会话,然后发送 GET 请求并读取相应数据。下载的图片以其 URL 中的文件名保存在本地,并在下载完成后打印消息。在 main 函数中,我们创建了一个 URL 列表并为每个 URL 启动一个协程,最后使用 asyncio.gather 函数等待所有协程执行完毕。
对比
多线程 | 多进程 | 协程 | |
优点 | 1. 共享内存,资源利用率高; 2. 线程切换开销小; 3. 便于编程和调试。 | 1. 进程间独立,不会相互影响; 2. 可以充分利用多核 CPU; 3. 鲁棒性好。 | 1. 协作式调度,无需加锁; 2. 编程简单,易于调试; 3. 轻量级,切换开销小。 |
缺点 | 1. 存在锁、信号量等同步机制; 2. 容易出现死锁、数据竞争等问题; 3. GIL 限制了多线程的并发性。 | 1. 进程切换开销大; 2. 进程间通信复杂; 3. 不易共享内存。 | 1. 不能充分利用多核 CPU; 2. 单个协程出现死循环等问题会导致整个程序挂起。 |
限制 | GIL 限制线程的并发性。 | 进程间通信需要额外的机制。 | 不能利用多核 CPU。 |
使用场景 | I/O 密集型任务,如网络通信、文件读写等。 | CPU 密集型任务,如算法计算、图像处理等;需要独立的进程环境。 | I/O 密集型任务,如异步 Web 应用、爬虫等。 |
性能对比 | 适中 | 较高 | 适中 |
当处理 I/O 密集型任务时,多线程和协程比多进程更适合,因为多进程间通信的复杂性增加了开销。在 CPU 密集型任务中,多进程的性能比多线程好,因为每个进程可以独立使用 CPU,而多线程受到 GIL 的限制。但是,多进程的切换开销比多线程大。对于同时处理 I/O 和 CPU 密集型任务的情况,可以使用线程池或进程池来平衡并发性能。
相关推荐
- js中arguments详解
-
一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...
- firewall-cmd 常用命令
-
目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...
- epel-release 是什么
-
EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...
- FullGC详解 什么是 JVM 的 GC
-
前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...
-
2024-10-26 08:50 citgpt
- 跨域(CrossOrigin)
-
1.介绍 1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。 通俗讲...
- 微服务架构和分布式架构的区别
-
1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...
- 深入理解与应用CSS clip-path 属性
-
clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...
-
2024-10-25 11:51 citgpt
- Request.ServerVariables 大全
-
Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...
- python操作Kafka
-
目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...
- Runtime.getRuntime().exec详解
-
Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...
- promise.all详解 promise.all是干什么的
-
promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...
-
2024-10-24 16:21 citgpt
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracleclient (56)
- springbatch (59)
- oracle恢复数据 (56)
- 简单工厂模式 (68)
- 函数指针 (72)
- fill_parent (135)
- java配置环境变量 (140)
- linux文件系统 (56)
- 计算机操作系统教程 (60)
- 静态ip (63)
- notifyicon (55)
- 线程同步 (58)
- xcode 4 5 (60)
- 调试器 (60)
- c0000005 (63)
- html代码大全 (61)
- header utf 8 (61)
- 多线程多进程 (65)
- require_once (60)
- 百度网盘下载速度慢破解方法 (72)
- 谷歌浏览器免费入口 (72)
- npm list (64)
- 网站打开速度检测 (59)
- 网站建设流程图 (58)
- this关键字 (67)