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

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

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

这个函数只是获取一个网页并将其保存到一个本地文件中,循环多次。无用但直截了当,因此很适合演示。让我们看看基准是什么吧。

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

现在,从这两张图表中可以注意到以下几点:

  • 在这两种情况下,单个进程的执行时间都比单个线程长。显然,进程比线程有更多的开销。
  • 对于受 CPU 限制的任务,多个进程的性能比多个线程要好。然而,当我们使用 8x 并行化时,这种差异就变得不那么明显了。由于我的笔记本电脑中的处理器是四核的,因此最多有四个进程可以有效地使用多核。所以当我使用更多的进程时,它的伸缩性就不好。但是,它仍然比线程性能好很多,因为线程根本不能利用多个核。
  • 对于 IO 绑定的任务,瓶颈不是 CPU。因此,GIL 带来的通常限制在这里不适用,多处理也没有优势。不仅如此,线程的轻量级开销实际上使它们比多处理更快,并且线程始终优于多处理。
差异、优缺点
  • 线程在相同的内存空间中运行;进程有单独的内存。
  • 从前面的观点来看:在线程之间共享对象更容易,但与此同时,你必须采取额外的措施来实现对象同步,以确保两个线程不会同时写入同一个对象,并且不会出现争用情况。
  • 由于对象同步增加了编程开销,多线程编程更容易出现错误。另一方面,多进程编程很容易实现。
  • 与进程相比,线程的开销更低;生成进程比线程花费更多的时间。
  • 由于 python 中 GIL 的局限性,线程不能利用多个 CPU 核实现真正的并行。多处理没有任何这样的限制。
  • 进程调度由操作系统处理,而线程调度则由 python 解释器完成。
  • 子进程是可中断和可终止的,而子线程不是。你必须等待线程终止或加入。

从所有这些讨论中,我们可以得出以下结论:

  1. 线程应该用于涉及 IO 或用户交互的程序。
  • 多处理应该用于 CPU 受限、计算密集型的程序。
从数据科学家的角度

典型的数据处理管道可分为以下步骤:

  • 读取原始数据并存储到主存储器或 GPU 中;
  • 使用 CPU 或 GPU 进行计算;
  • 将挖掘出的信息存储在数据库或磁盘中。

让我们来探索如何在这些任务中引入并行性,从而加快它们的速度。

步骤 1 包括了从磁盘读取数据,因此很明显磁盘 IO 将成为此步骤的瓶颈。正如我们所讨论的,线程是并行这种操作的最佳选择。同样,步骤 3 也是引入线程的理想候选步骤。

但是,步骤 2 包含涉及 CPU 或 GPU 的计算。如果是基于 CPU 的任务,那么使用线程将毫无用处;相反,我们必须进行多处理。只有这样,我们才能利用 CPU 的多个核并实现并行性。如果这是一个基于 GPU 的任务,因为 GPU 已经在硬件级别实现了一个大规模并行化的体系结构,那么使用正确的接口(库和驱动程序)与 GPU 交互应该可以处理剩下的事情。

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

现在你可能会想,「我的数据管道看起来与此有些不同;我有一些任务并不真正适合这个通用框架。」不过,在这里你应该考虑的因素是:

  • 你的任务是否有任何形式的 IO
  • IO 是否是程序的瓶颈
  • 你的任务是否取决于 CPU 的大量计算

考虑到这些因素,再加上上面的要点,你应该能够做出决定。另外,请记住,你不必在整个程序中使用单一形式的并行,而是应该在程序的不同部分使用不同的并行。

现在我们来看看数据科学家可能面临的两个常见场景,以及如何使用并行计算来加速它们。

场景 1:下载电子邮件

假设你想分析自己创业公司收件箱中的所有电子邮件,并了解其趋势:谁是最频繁的发件人,电子邮件中出现的最常见关键字是什么,一周中的哪一天或一天中的哪一小时收到的电子邮件最多,等等。当然,这个项目的第一步是将电子邮件下载到你的计算机上。

首先,让我们按顺序进行,而不使用任何并行化。下面是要使用的代码,应该非常简单明了。有一个下载电子邮件的功能,它以电子邮件 ID 列表作为输入,并按顺序下载它们。这个函数一次调用 100 个电子邮件的 ID 列表。

  1. import imaplib  
  2. import time  
  3. IMAP_SERVER = 'imap.gmail.com'  
  4. USERNAME = 'username@gmail.com'  
  5. PASSWORD = 'password'  
  6.  
  7. def download_emails(ids): 
  8.    client = imaplib.IMAP4_SSL(IMAP_SERVER) 
  9.    client.login(USERNAME, PASSWORD) 
  10.    client.select() 
  11.    for i in ids: 
  12.        print(f'Downloading mail id: {i.decode()}') 
  13.        _, data = client.fetch(i, '(RFC822)') 
  14.        with open(f'emails/{i.decode()}.eml', 'wb') as f: 
  15.            f.write(data[0][1]) 
  16.    client.close() 
  17.    print(f'Downloaded {len(ids)} mails!')  
  18.  
  19. start = time.time()  
  20.  
  21. client = imaplib.IMAP4_SSL(IMAP_SERVER)  
  22. client.login(USERNAME, PASSWORD)  
  23. client.select()  
  24. _, ids = client.search(None, 'ALL')  
  25. ids = ids[0].split()  
  26. ids = ids[:100]  
  27. client.close()  
  28.  
  29. download_emails(ids)  
  30. print('Time:', time.time() - start) 

所用时间:35.65300488471985 秒。

(编辑:核心网)

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

热点阅读