并发和并行 | Python中实现多线程 threading 和多进程 multiprocessing
并发和并行 | Python中实现多线程 threading 和多进程 multiprocessing
昨天晚上组会轮到我汇报技术内容,最近正在和 ray 以及 spark 打交道,索性讲一下并发和并行。反正大家都是管理学院的,平时很少接触这种,因此这个选题不大可能因为内容基础而贻笑大方。
本文摆一摆并发和并行。附上很简单的 Python 代码,涉及到自带库 threading 和 multiprocessing 的使用。
并发和并行
咱们简单用多线程对应并发,多进程对应并行。多线程并发更强调充分利用性能;多进程并行更强调提升性能上限。
我用非常简单且不那么严谨的比喻来说明。
多线程
一个 CPU 相当于一个学生。
一个学生一周开一次组会,换句话说一周给老师汇报一次工作。
老师一般会给学生同时布置几个任务,比如做比赛、做项目、读论文,学生可能周一做做比赛、周二读读论文、周三做做项目... 到了组会,他就把三件事都拿出来汇报,老师很欣慰,因为在老师的视角里:学生这三件事是同时在做的。
多线程也是同一个道理,假设你的手机只有一块单核 CPU 。你的 CPU 这 0.01 秒用来播放音乐,下 0.01 秒用来解析网页... 在你的视角里:播放音乐和解析网页是同时进行的。你大可以畅快地边听音乐边网上冲浪
何谓充分利用性能? 如果这学生只有一项工作,那他这一周可能只需要花费两天来做任务,剩下时间摸鱼(针不搓,三点钟饮茶先!)。因此,我们用「多线程」来让学生实现『并发』,充分利用学生能力。
在实际情况中,多线程、高并发这些词语更多地出现在服务端程序里。比如一个网络连接由一个线程负责,一块 CPU 可以负责处理多个异步的请求,大大提升了 CPU 利用率。
多进程
多个 CPU ( CPU 的多核)相当于多个学生。
一个任务可以拆成几个任务相互协作、同时进行,则是多进程。
比如研究生课程,老师非得留个论文作业,都研究生了我去,留啥大作业。
那咱就多线程并行搞呗。确定了大概思路,剩下的一股脑写就行。咱队伍里一共甲乙丙丁四名同学,那就:
- 甲同学负责 Introduction
- 乙同学负责 Background
- 丙同学负责 Related Works
- 丁同学负责 Methodology
这是乙同学提出异议:不应该是先完成 Introduction 再写 Background ,一个个来嘛?
大哥,都研究生了嗷,作业糊弄糊弄差不多得了啊。让你写你就写。
可以预知,上述四部分同时进行,怎么也比一个人写四块要快。
所以说 多进程并行提升性能上限 。
在实际情况中,多进程更多地与高性能计算、分布式计算联系在一起。
Python 实现
首先声明咱的实验环境。
> python --version
Python 3.8.5
咱们设置个任务:求数的欧拉函数值。
def euler_func(n: int) -> int:
res = n
i = 2
while i <= n // i:
if n % i == 0:
res = res // i * (i - 1)
while (n % i == 0): n = n // i
i += 1
if n > 1:
res = res // n * (n - 1)
return res
求一个数的欧拉函数值可能很快,但是一堆数呢?
所以咱想着用并行完成这个任务。
咱们把任务分成三份。
task1 = list(range(2, 50000, 3)) # 2, 5, ...
task2 = list(range(3, 50000, 3)) # 3, 6, ...
task3 = list(range(4, 50000, 3)) # 4, 7, ...
def job(task: List):
for t in task:
euler_func(t)
来看看平平无奇的正常串行。
@timer
def normal():
job(task1)
job(task2)
job(task3)
完成了 task1
再完成 task2
... 行,没毛病。
看看多线程?
import threading as th
@timer
def mutlthread():
th1 = th.Thread(target=job, args=(task1, ))
th2 = th.Thread(target=job, args=(task2, ))
th3 = th.Thread(target=job, args=(task3, ))
th1.start()
th2.start()
th3.start()
th1.join()
th2.join()
th3.join()
再看看多进程?
import multiprocessing as mp
@timer
def multcore():
p1 = mp.Process(target=job, args=(task1, ))
p2 = mp.Process(target=job, args=(task2, ))
p3 = mp.Process(target=job, args=(task3, ))
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
上述代码的逻辑是这样的:
- 我创建线程/进程,其生来的目的就是完成任务
job(task1)
或job(task2)
、job(task3)
,注意这里函数名和参数被分开了target=job, args=(task1, )
- 然后
start()
,告诉线程/进程:你可以开始干活了 - 他们自己干自己的,咱们程序主逻辑还得继续往下运行
- 到
join()
这里,咱们是指让线程/进程阻塞住咱的主逻辑,比如p1.join()
是指:p1
不干完活,我主逻辑不往下进行(属于是「阻塞」) - 这样,我们的函数
multcore
结束后,一定其中的线程/进程任务都完成了
咱看看结果:
if __name__ == '__main__':
print("同步串行:")
normal()
print("多线程并发:")
mutlthread()
print("多进程并行:")
multcore()
# 下面是结果
同步串行:
timer: using 0.24116 s
多线程并发:
timer: using 0.24688 s
多进程并行:
timer: using 0.13791 s
结果不太对,按理说,多进程并行
的耗时应该是同步串行
的三分之一,毕竟三个同等体量的任务在同时进行。
多线程并发
比同步串行
慢是应该的,因为多线程并发
和同步串行
的算力是一样的,但是多线程并发得在各个任务间来回切换,导致更慢。
你问 @timer
是什么意思?哦,这个是我写的修饰器,如下。
def timer(func):
@wraps(func)
def inner_func():
t = time.time()
rts = func()
print(f"timer: using {time.time() - t :.5f} s")
return rts
return inner_func
不太明白『Python修饰器』的老铁,不如给我点个「在看」,再关注下我,咱们以后详细道来。
我是小拍,微信 PiperLHJ ,感谢关注与在看。
并发和并行 | Python中实现多线程 threading 和多进程 multiprocessing的更多相关文章
- python中的多线程【转】
转载自: http://c4fun.cn/blog/2014/05/06/python-threading/ python中关于多线程的操作可以使用thread和threading模块来实现,其中th ...
- Python中的多线程编程,线程安全与锁(二)
在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...
- python中的多线程编程与暂停、播放音频的结合
先给两个原文链接: https://blog.csdn.net/u013755307/article/details/19913655 https://www.cnblogs.com/scolia/p ...
- python中的多线程
一个程序可以理解为一个进程,这个进程有其代号,可以依据这个代号将其杀死. 一个进程肯定有且只有一个主线程,他可以有很多子线程. 运行一个任务如果可以有许多子线程同时去做,当然会提高效率. 但是,在py ...
- python中的多线程和多进程
一.简单理解一下线程和进程 一个进程中可有多个线程,线程之间可共享内存,进程间却是相互独立的.打比方就是,进程是火车,线程是火车厢,车厢内人员可以流动(数据共享) 二.python中的多线程和多进程 ...
- Python 中 logging 日志模块在多进程环境下的使用
因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,Python 中 logging 日志模块在多进程环境下的使用 使用 Pytho ...
- 第十五章、python中的进程操作-开启多进程
目录 第十五章.python中的进程操作-开启多进程 一.multprocess模块 二.multprocess.process模块 三.Process()对象方法介绍 四.Process()对象属性 ...
- 并发编程---线程 ;python中各种锁
一,概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 --车间负责把资源整合到 ...
- 2016/1/2 Python中的多线程(1):线程初探
---恢复内容开始--- 新年第一篇,继续Python. 先来简单介绍线程和进程. 计算机刚开始发展的时候,程序都是从头到尾独占式地使用所有的内存和硬件资源,每个计算机只能同时跑一个程序.后来引进了一 ...
- Python中的多线程编程,线程安全与锁(一)
1. 多线程编程与线程安全相关重要概念 在我的上篇博文 聊聊Python中的GIL 中,我们熟悉了几个特别重要的概念:GIL,线程,进程, 线程安全,原子操作. 以下是简单回顾,详细介绍请直接看聊聊P ...
随机推荐
- insufficient permission for adding an object to repository database .git/objects
1.出错截图: 有时候使用软件项目管理系统github时候,会出现一些问题截图如下: 2.出错原因 从出错的地方就知道是因为权限不足导致,回想一下,在链接远程服务器时候,不小心切换为管理员权限进行了g ...
- 饿了么Element UI之Upload组件图片上传【原创】
图片文件换汤不换药,只要注意前端的写法即可 1.饿了么组件可以利用 http-request 的属性对上传进行自定义 :http-request="uploadFile" 2.设置 ...
- jeecg平台相关01-vue2迁移到vue3
01-vue2迁移到vue3 嵌套: datasource: master: url: jdbc:mysql://127.0.0.1:3306/jeecg-boot-vue3?characterEnc ...
- Go语言学习 _基础04 _Map&Set
Go语言学习 _基础04 _Map&Set 1.map package map_test import ( "fmt" "testing" ) func ...
- 解决MobaXterm自动断开连接,亲测有效~
场景: 使用MobaXterm工具通过SSH连接Linux服务器,如果一段时间没有操作,MobaXterm会把连接自动断开,这个设定很是不方便.通过更改下面的设置可以使SSH保持长连接,不会自动断开.
- 你的WAF是否真的安全?雷池社区版的安全能力测试
你的WAF能力如何?雷池社区版的安全能力测试 最近雷池社区版很火,各大技术群都在讨论 什么是雷池? 引用官网文档的一段话: SafeLine,中文名 "雷池",是一款简单好用, 效 ...
- 基于 .NET 的开源工作流引擎框架
前言 工作流管理成为了提高应用灵活性和可维护性的重要手段.Elsa 作为一款针对 .NET 平台的强大工作流库,为开发者提供了在各种 .NET 应用中轻松集成和执行复杂工作流的能力. 本文将详细介绍 ...
- 利用 word VBA 将投标文件偏离参数表列数据拷贝至技术偏差表中
使用 vba 将正偏离参数表的第一列信息复制粘贴至对应的技术偏离表的第4列中.需要同时打开两个 word 文件,在技术偏差表中打开 VBE(可以用ctrl + f11 快捷键),插入模块. 忽略格式的 ...
- linux模拟HID USB设备及wireshark USB抓包配置
目录 1. 内核配置 2. 设备配置 附 wireshark USB抓包配置 笔者开发USB设备时的一些记录 1. 内核配置 内核启用USB Gadget,使用fs配置usb device信息. De ...
- redis 使用lua 生成流水号
在实际的业务场景中,我们会用到流水号. 之前的流水号做法是,使用redis的全局锁.然后对数据库进行更新,数据库更新 这个也会有一些问题,比如对于同一个流水号,多个线程去更新,由于事务比较长,那么就会 ...