加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

想提高计算速度?作为数据科学家你应该知道这些Python多线程、进程知识

发布时间:2019-09-19 12:32:25 所属栏目:建站 来源:skura
导读:每个数据科学项目迟早都会面临一个不可避免的挑战:速度问题。使用更大的数据集会导致处理速度变慢,因此最终必须想办法优化算法的运行时间。正如你们大多数人已经知道的,并行化是这种优化的必要步骤。python 为并行化提供了两个内置库:多处理和线程。在
副标题[/!--empirenews.page--]

每个数据科学项目迟早都会面临一个不可避免的挑战:速度问题。使用更大的数据集会导致处理速度变慢,因此最终必须想办法优化算法的运行时间。正如你们大多数人已经知道的,并行化是这种优化的必要步骤。python 为并行化提供了两个内置库:多处理和线程。在这篇文章中,我们将探讨数据科学家如何在两者之间进行选择,以及在这样做时应注意哪些因素。

想提高计算速度?作为数据科学家你应该知道这些Python多线程、进程知识

并行计算与数据科学

众所周知,数据科学是处理大量数据并从中提取有用见解的科学。通常情况下,我们对数据执行的操作很容易并行化,这意味着不同的处理代理可以一次对数据执行一个操作,最后进行组合以获得完整的结果。

为了更好地解释并行性,让我们拿一个真实世界的例子作为类比。假设你需要打扫你家的三个房间。你可以自己打扫,打扫完一个再打扫另一个,也可以让你的两个兄弟姐妹帮你打扫,每个人打扫一个房间。在后一种方法中,每个人完成整个任务的一部分,从而减少了完成任务所需的总时间。这就是实际中的并行性。

并行处理可以用 python 以两种不同的方式实现:多处理和线程。

多处理与线程:理论

基本上,多处理和线程是实现并行计算的两种方法,分别使用进程和线程作为处理代理。为了理解它们的工作原理,我们必须搞清楚什么是进程和线程。

想提高计算速度?作为数据科学家你应该知道这些Python多线程、进程知识

进程

进程是正在执行的计算机程序的实例。每个进程都有自己的内存空间,用来存储正在运行的指令,以及需要存储和访问才能执行的任何数据。

线程

线程是进程的组件,可以并行运行。一个进程中可以有多个线程,它们共享相同的内存空间,即父进程的内存空间。这意味着要执行的代码以及程序中声明的所有变量将由所有线程共享。

想提高计算速度?作为数据科学家你应该知道这些Python多线程、进程知识

例如,让我们回想一下正在你的计算机上运行的程序。你可能正在浏览器中阅读本文,浏览器可能打开了多个选项卡。你也可以同时通过 Spotify 桌面应用程序收听音乐。浏览器和 spotify 应用程序是不同的进程;每个进程都可以使用多个进程或线程来实现并行性。浏览器中的不同选项卡可能在不同的线程中运行。Spotify 可以在一个线程中播放音乐,在另一个线程中从 Internet 下载音乐,并使用第三个线程显示图形用户界面。这称为多线程。对多个进程进行多处理也可以做到这一点。事实上,像 chrome 和 firefox 这样的大多数现代浏览器使用多处理,而不是多线程来处理多个选项卡。

技术细节

一个进程的所有线程都存在于同一个内存空间中,而进程有各自的内存空间。

与进程相比,线程更轻量级,开销更低。生成进程比生成线程慢一点。

在线程之间共享对象更容易,因为它们共享相同的内存空间。为了实现同一个进程间通信,我们必须使用某种 IPC (inter-process communication) 模型,它通常由 OS 提供。

并行计算的陷阱

将并行性引入程序并不总是一个正和博弈,也有一些陷阱需要注意。其中,最重要的是下面的这些问题。

  • 竞争条件:正如我们已经讨论过的,线程有一个共享内存空间,因此它们可以访问共享变量。当多个线程试图同时更改同一个变量时,会出现竞争条件。线程调度程序可以在线程之间任意交换,因此我们无法知道线程尝试更改数据的顺序。这可能会导致两个线程中的任何一个出现不正确的行为,特别是当线程决定基于变量的值执行某些操作时。为了防止这种情况发生,可以在修改变量的代码段周围放置互斥锁,以便一次只能有一个线程写入变量。
  • 饥饿:当一个线程在较长时间内被拒绝访问某个特定的资源时,就会发生饥饿,在这种情况下,整个程序的速度会减慢。这可能是由于线程调度算法设计不当而产生的意外副作用。
  • 死锁:过度使用互斥锁也有一个缺点——它会在程序中引入死锁。死锁是一个线程等待另一个线程释放锁时的状态,但另一个线程需要一个资源来完成第一个线程保持的操作。这样,两个线程都会停止,程序也会停止。死锁可以被认为是饥饿的极端情况。为了避免这种情况,我们必须小心不要引入太多相互依赖的锁。
  • 活锁:活锁是指线程在循环中继续运行,但没有任何进展。这也是由于互斥锁设计不当和使用不当造成的。
python 中的多处理和线程

全局解释器锁

说到 python,有一些奇怪的地方需要记住。我们知道线程共享相同的内存空间,因此必须采取特殊的预防措施,以便两个线程不会写入相同的内存位置。CPython 解释器使用名为 GIL 的机制或全局解释器锁来处理这个问题。

python wiki 上面的资料:

  • 在 CPython 中,全局解释器锁(GIL)是一个互斥锁,它保护对 python 对象的访问过程,防止多个线程同时执行 python 字节码。这个锁是必要的,这主要是因为 CPython 的内存管理不是线程安全的。

了解 python GIL 的详细信息,请查看 。

GIL 完成了任务,但付出了代价。它在解释器级别上有效地序列化指令。其工作原理如下:任何线程要执行任何函数,都必须获取全局锁。一次只有一个线程可以获取该锁,这意味着解释器最终会以串行方式运行指令。这种设计使得内存管理线程安全,但结果是,它根本不能利用多个 cpu 内核。在单核 cpu 中,这不是什么大问题。但是如果你使用多核 cpu,这个全局锁最终会成为一个瓶颈。

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读