我试图了解多处理优于线程的优势。 我知道多处理可以解决Global Interpreter Lock问题,但是还有什么其他优点,并且线程不能做同样的事情?


#1楼

关键优势是隔离。 崩溃进程不会导致其他进程崩溃,而崩溃的进程可能会对其他线程造成严重破坏。


#2楼

threading模块使用线程, multiprocessing模块使用进程。 不同之处在于线程在相同的内存空间中运行,而进程具有单独的内存。 这使得在具有多处理的进程之间共享对象变得有点困难。 由于线程使用相同的内存,因此必须采取预防措施,否则两个线程将同时写入同一内​​存。 这就是全局解释器锁的用途。

产卵过程比产生线程慢一点。 一旦它们运行,就没有太大区别。


#3楼

另一件未提及的事情是它取决于您在速度方面使用的操作系统。 在Windows中,进程成本很高,因此在Windows中线程会更好,但是在unix进程中它们比它们的windows变体更快,因此在unix中使用进程更加安全,而且可以快速生成。


#4楼

线程的工作是使应用程序能够响应。 假设您有数据库连接,并且需要响应用户输入。 如果没有线程,如果数据库连接繁忙,应用程序将无法响应用户。 通过将数据库连接拆分为单独的线程,可以使应用程序更具响应性。 此外,由于两个线程都在同一个进程中,因此它们可以访问相同的数据结构 - 良好的性能以及灵活的软件设计。

请注意,由于GIL,应用程序实际上并没有同时执行两项操作,但我们所做的是将数据库上的资源锁定放入一个单独的线程中,以便可以在它与用户交互之间切换CPU时间。 CPU时间在线程之间得到限制。

多处理是指您确实希望在任何给定时间完成多项操作的时间。 假设您的应用程序需要连接到6个数据库并对每个数据集执行复杂的矩阵转换。 将每个作业放在一个单独的线程中可能会有所帮助,因为当一个连接空闲时,另一个可能会获得一些CPU时间,但是处理不会并行完成,因为GIL意味着您只使用一个CPU的资源。 通过将每个作业置于多处理过程中,每个作业都可以在其自己的CPU上运行并以最高效率运行。


#5楼

以下是我想出的一些优点/缺点。

优点

  • 单独的内存空间
  • 代码通常很简单
  • 利用多个CPU和核心
  • 避免cPython的GIL限制
  • 消除对同步原语的大多数需求,除非您使用共享内存(相反,它更像是IPC的通信模型)
  • 子进程是可中断/可杀死的
  • Python multiprocessing模块包含有用的抽象,其界面非常类似于threading.Thread
  • 必须使用cPython进行CPU绑定处理

缺点

  • IPC更复杂,开销更大(通信模型与共享内存/对象)
  • 更大的内存占用

穿线

优点

  • 轻量级 - 内存占用少
  • 共享内存 - 更容易从另一个上下文访问状态
  • 允许您轻松制作响应式用户界面
  • 正确释放GIL的cPython C扩展模块将并行运行
  • I / O绑定应用程序的绝佳选择

缺点

  • cPython - 受GIL限制
  • 不可中断/可杀
  • 如果不遵循命令队列/消息泵模型(使用Queue模块),则手动使用同步原语成为必需(锁定粒度需要决策)
  • 代码通常难以理解并且正确 - 竞争条件的可能性会急剧增加

#6楼

) has to be taken into account. 其他答案更多地关注多线程与多处理方面,但在python中必须考虑全局解释器锁( )。 ) of threads are created, generally they will not increase the performance by times, as it will still be running as a single threaded application. 当创建更多数量(比如 )的线程时,通常它们不会将性能提高倍,因为它仍将作为单线程应用程序运行。 GIL是一个全局锁,可以锁定所有内容,并且只允许单个线程执行,只使用一个内核。 在使用Numpy,Network,I / O等C扩展的地方,性能确实会增加,在那里完成了大量后台工作并发布了GIL。
is used, there is only a single operating system level thread while python creates pseudo-threads which are completely managed by threading itself but are essentially running as a single process. 因此,当使用时,只有一个操作系统级线程,而python创建伪线程,这些线程完全由线程本身管理,但基本上作为单个进程运行。 抢占发生在这些伪线程之间。 如果CPU以最大容量运行,您可能希望切换到多处理。
现在,如果是自包含的执行实例,您可以改为选择池。 但是在数据重叠的情况下,您可能希望进程通信,您应该使用multiprocessing.Process


#7楼

进程可能有多个线程。 这些线程可以共享内存,并且是进程内的执行单元。

进程在CPU上运行,因此线程驻留在每个进程下。 流程是独立运行的单个实体。 如果要在每个进程之间共享数据或状态,可以使用内存存储工具,如Cache(redis, memcache)FilesDatabase


#8楼

正如问题中所提到的,Python中的多处理是实现真正并行性的唯一真正方法。 多线程无法实现这一点,因为GIL会阻止线程并行运行。

因此,线程在Python中可能并不总是有用,事实上,甚至可能会导致性能下降,具体取决于您要实现的目标。 例如,如果您正在执行CPU绑定任务,例如解压缩gzip文件或3D渲染(任何CPU密集型),那么线程实际上可能会妨碍您的性能而不是帮助。 在这种情况下,您可能希望使用多处理,因为此方法实际上并行运行,并有助于分配手头任务的权重。 可能会有一些开销因为多处理涉及将脚本的内存复制到每个子进程中,这可能会导致更大的应用程序出现问题。

但是,当您的任务受IO限制时, 多线程会很有用。 例如,如果您的大部分任务都涉及等待API调用 ,那么您将使用多线程,因为为什么不在等待时在另一个线程中启动另一个请求,而不是让您的CPU闲置。

TL; DR

  • 多线程是并发的,用于IO绑定任务
  • 多处理实现了真正的并行性,并用于CPU绑定任务

#9楼

Python文档引用

我突出了关于Process vs Threads和GIL的关键Python文档引用: CPython中的全局解释器锁(GIL)是什么?

进程与线程实验

为了更具体地展示差异,我做了一些基准测试。

在基准测试中,我为8个超线程 CPU上的各种线程数量计算了CPU和IO绑定工作。 每个线程提供的工作总是相同的,这样更多的线程意味着提供更多的工作。

结果是:

绘制数据 。

结论:

  • 对于CPU绑定工作,多处理总是更快,可能是由于GIL

  • 用于IO绑定工作。 两者速度完全相同

  • 由于我使用的是8个超线程机器,因此线程只能扩展到大约4倍而不是预期的8倍。

    与C POSIX CPU绑定工作形成对比,达到预期的8倍加速: “真实”,“用户”和“系统”在时间输出(1)中的含义是什么?

    TODO:我不知道这个的原因,必须有其他Python低效率发挥作用。

测试代码:

#!/usr/bin/env python3import multiprocessing
import threading
import time
import sysdef cpu_func(result, niters):'''A useless CPU bound function.'''for i in range(niters):result = (result * result * i + 2 * result * i * i + 3) % 10000000return resultclass CpuThread(threading.Thread):def __init__(self, niters):super().__init__()self.niters = nitersself.result = 1def run(self):self.result = cpu_func(self.result, self.niters)class CpuProcess(multiprocessing.Process):def __init__(self, niters):super().__init__()self.niters = nitersself.result = 1def run(self):self.result = cpu_func(self.result, self.niters)class IoThread(threading.Thread):def __init__(self, sleep):super().__init__()self.sleep = sleepself.result = self.sleepdef run(self):time.sleep(self.sleep)class IoProcess(multiprocessing.Process):def __init__(self, sleep):super().__init__()self.sleep = sleepself.result = self.sleepdef run(self):time.sleep(self.sleep)if __name__ == '__main__':cpu_n_iters = int(sys.argv[1])sleep = 1cpu_count = multiprocessing.cpu_count()input_params = [(CpuThread, cpu_n_iters),(CpuProcess, cpu_n_iters),(IoThread, sleep),(IoProcess, sleep),]header = ['nthreads']for thread_class, _ in input_params:header.append(thread_class.__name__)print(' '.join(header))for nthreads in range(1, 2 * cpu_count):results = [nthreads]for thread_class, work_size in input_params:start_time = time.time()threads = []for i in range(nthreads):thread = thread_class(work_size)threads.append(thread)thread.start()for i, thread in enumerate(threads):thread.join()results.append(time.time() - start_time)print(' '.join('{:.6e}'.format(result) for result in results))

GitHub上游+在同一目录上绘制代码 。

在带有CPU的联想ThinkPad P51笔记本电脑上测试Ubuntu 18.10,Python 3.6.7:Intel Core i7-7820HQ CPU(4核/ 8线程),RAM:2x三星M471A2K43BB1-CRC(2x 16GiB),SSD:三星MZVLB512HAJQ- 000L7(3,000 MB / s)。

可视化在给定时间运行的线程

这篇文章https://rohanvarma.me/GIL/告诉我,只要使用threading.Threadtarget=参数调度线程,就可以运行回调,对于multiprocessing.Process

这允许我们确切地查看每次运行的线程。 完成后,我们会看到类似的东西(我制作了这个特定的图形):

+-----------+--------------------------------------+
|Thread   1 |********     ************             |
|         2 |        *****            *************|
+-----------+--------------------------------------+
|Process  1 |***  ************** ******  ****      |
|         2 |** **** ****** ** ********* **********|
+-----------+--------------------------------------+

这表明:

  • 线程由GIL完全序列化
  • 进程可以并行运行

#10楼

  • 多处理增加了CPU以提高计算能力。
  • 多个进程同时执行。
  • 创建流程既耗时又耗费资源。
  • 多处理可以是对称的或非对称的。
  • Python中的多处理库使用单独的内存空间,多个CPU内核,绕过CPython中的GIL限制,子进程可以运行(例如程序中的函数调用)并且更容易使用。
  • 该模块的一些警告是更大的内存占用,IPC更复杂,更多的开销。

MULTITHREADING

  • 多线程创建单个进程的多个线程以提高计算能力。
  • 同时执行单个进程的多个线程。
  • 创建线程在时间和资源方面都是经济的。
  • 多线程库是轻量级的,共享内存,负责响应式UI,适用于I / O绑定应用程序。
  • 该模块不可用,并且受GIL限制。
  • 多个线程存在于同一空间中的同一进程中,每个线程将执行特定任务,拥有自己的代码,自己的堆栈内存,指令指针和共享堆内存。
  • 如果一个线程有内存泄漏,它可能会损坏其他线程和父进程。

使用Python进行多线程和多处理的示例

Python 3具有启动并行任务的功能 。 这使我们的工作更轻松。

它具有线程池和进程池 。

以下是一个见解:

ThreadPoolExecutor示例

import concurrent.futures
import urllib.requestURLS = ['http://www.foxnews.com/','http://www.cnn.com/','http://europe.wsj.com/','http://www.bbc.co.uk/','http://some-made-up-domain.com/']# Retrieve a single page and report the URL and contents
def load_url(url, timeout):with urllib.request.urlopen(url, timeout=timeout) as conn:return conn.read()# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:# Start the load operations and mark each future with its URLfuture_to_url = {executor.submit(load_url, url, 60): url for url in URLS}for future in concurrent.futures.as_completed(future_to_url):url = future_to_url[future]try:data = future.result()except Exception as exc:print('%r generated an exception: %s' % (url, exc))else:print('%r page is %d bytes' % (url, len(data)))

ProcessPoolExecutor

import concurrent.futures
import mathPRIMES = [112272535095293,112582705942171,112272535095293,115280095190773,115797848077099,1099726899285419]def is_prime(n):if n % 2 == 0:return Falsesqrt_n = int(math.floor(math.sqrt(n)))for i in range(3, sqrt_n + 1, 2):if n % i == 0:return Falsereturn Truedef main():with concurrent.futures.ProcessPoolExecutor() as executor:for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):print('%d is prime: %s' % (number, prime))if __name__ == '__main__':main()

#11楼

我在大学里学到的大部分答案都是正确的。 在不同平台上的实践中(总是使用python),产生多个线程最终会产生一个进程。 区别在于多个核心共享负载,而不是只有1个核心处理100%的所有内容。 因此,如果你在4核PC上产生例如10个线程,你最终只会获得25%的cpu功率!! 如果你产生10个进程,你最终将以100%的cpu处理结果(如果你没有其他限制)。 我不是所有新技术的专家。 我回答自己的真实经验背景

多处理与线程Python相关推荐

  1. 什么是Python线程?Python线程如何创建?

    相信正在学习Python技术或者对Python语言有一定了解的人对于Python线程应该都不陌生,但是也有刚接触Python的小伙伴对于Python线程并不了解,今天小编就跟大家聊聊什么是Python ...

  2. python多线程结束线程_Python线程– Python多线程

    python多线程结束线程 Python threading module is used to implement multithreading in python programs. In thi ...

  3. python删除线程,python线程基础

    一 基本概念 1 并行和并发 1 并行,parallel 同时做某些事,可以互不干扰的同一时刻做几件事 如高速公路上的车道,同一时刻,可以有多个互不干扰的车运行 在同一时刻,每条车道上可能同时有车辆在 ...

  4. linux查看python线程,Python多线程详解

    线程概念: 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务.线程 ...

  5. python多线程并发编程技术_同步线程 - Python并发编程教程™

    线程同步可以定义为一种方法,借助这种方法,可以确信两个或更多的并发线程不会同时访问被称为临界区的程序段. 另一方面,正如我们所知道的那样,临界区是共享资源被访问的程序的一部分. 因此,同步是通过同时访 ...

  6. 多线程-threading和进程VS线程(python 版)

    多线程-threading python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用 1. 使用threading模块 ...

  7. python定时器 是线程吗_定时器中断线程python

    我一直试图在python中创建一个精确的计时器,或者一个OS允许的精确计时器.但这似乎比我最初想象的要复杂. 这就是我想要的工作方式:from time import sleep from threa ...

  8. python 子线程阻塞主线程,Python多处理/线程阻塞主线程

    我正在尝试用Python编写一个程序.我想写的是一个脚本,它会立即向用户返回友好的消息,但会在后台生成一个很长的子进程,该子进程处理多个不同的文件并将它们写入一个原始文件.我已经做了一些关于线程和处理 ...

  9. 搞事情 -- python之线程

    简介 操作系统线程理论 线程概念的引入背景 线程的特点 进程和线程的关系 使用线程的实际场景 用户级线程和内核级线程(了解) 线程和python 理论知识 线程的创建Threading.Thread类 ...

最新文章

  1. .NET3.5中的高性能 Socket API
  2. @mapperscan mapper还是无法引用_高能来了!Java的四大引用
  3. 笔记-高项案例题-2016年下-计算题
  4. pythonmsgbox怎么使用_如何使用tkinter的messagebox
  5. linux有防火墙么,Linux防火墙Firewall和Iptables的使用
  6. [ASP.NET Core 3框架揭秘] 跨平台开发体验: Docker
  7. swift 4.2 - 根据字符串 push指定控制器
  8. SDNU 1272.SL的秘密
  9. Python:通过执行100万次打印来比较C和python的性能,以及用C和python结合来解决性能问题的方法 ....
  10. 【MATLAB】freqz2()使用方法官方文档翻译
  11. jdk和jre安装配置
  12. IT计算机实习:JAVA实习报告范文(一)
  13. linux查看文件夹大小命令
  14. 程序员表白代码php,火热的程序员表白方式,调皮弹窗表白代码,赶紧拿去试试吧...
  15. Django order by 高级用法
  16. 传网络安全提供商FireEye有意收购CyberArk
  17. 简单python爬虫爬取游戏wiki立绘
  18. ss3ex集成Beet记录日志
  19. png转icon的一个软件
  20. js元素选择器-js更具name获取元素中的元素

热门文章

  1. Android 页面进行镜像反转-面试
  2. Android RecycleView ScrollBy不生效
  3. 源码解析:解析掌阅X2C 框架
  4. Win10双系统CentOS7安装完无法启动Win10的解决方法
  5. android自定义WaveView水波纹控件
  6. linux 互斥锁销毁_c-销毁锁定的互斥锁时pthread_mutex_destroy的正...
  7. SDOI2014 LIS
  8. ELK出现unassigned_shards查看及删除
  9. A Bug's Life(向量偏移)
  10. 读取xml忽略dtd验证