美文网首页真格量化
Python的多线程和多进程——从一个爬虫任务谈起

Python的多线程和多进程——从一个爬虫任务谈起

作者: ce2a5fc7b1e4 | 来源:发表于2019-07-06 08:51 被阅读1次

本文的目的是解释为什么在Python中需要多线程和多处理,何时使用多线程和多进程,以及它们能怎样提高我们程序的性能。

假设我们的量化模型需要从多个网站爬取一些数据,我们将要对比用单线程和多线程的方法有何性能上的差别。

1,单线程,单进程

在单线程、单进程中,我们将用for循环读取一个url列表。

如您所见,我们只是使用for循环一个接一个地遍历url并读取响应。我们可以使用IPython的%%time函数对消耗的时间进行统计,这个读取13个网页的任务大约需要12秒钟。

2,多线程

现在我们改进一下这个程序,我们可以将读取url的任务分配给多个线程来完成,而不是只让一个线程去逐一读取。

比如4个线程:

8个线程:

16个线程:

用到16个线程时,这个任务的耗时已经从12.3秒缩短到了1.32秒。

使用多线程可以显著加快许多与io绑定的任务。在这里,读取url所花费的大部分时间是由于网络延迟。与io绑定的程序大部分时间都在等待输入/输出,无所事事。这可能是来自网络、数据库、文件甚至用户的I/O。这种I/O往往要花费大量的时间,因为源本身可能需要在传递I/O之前执行自己的处理。例如,CPU的工作速度比网络连接传输数据的速度快得多。

多线程可以显著提高我们爬取网页任务的效率。

3,多重处理

另一个可以提高效率的手段是多重处理。

比如我们有一个任务是计算100万以内所有质数的和。

如果只用单个进程:

如果使用多进程:

和多线程类似,多进程也是将任务(比如判断一系列数是否是质数)拆分再汇总,以此提高效率。

由于现代CPU通常有多个核心,我们可以通过使用多处理模块来加快CPU绑定任务的速度。CPU绑定任务是花费大部分时间在CPU上执行计算的程序(数学计算、图像处理等)。如果计算可以彼此独立地执行,我们就可以将它们分配到可用的CPU内核中,从而显著提高处理速度。

我们所要做的就是:

1,定义要应用的函数

2,准备要应用功能的项目列表

3,使用Pool生成进程。传递给Pool()的数字将是生成的进程数。在with语句中嵌入可以确保在完成执行后终止进程。

4,使用池进程的map函数组合输出。映射函数的输入是要应用于每个项的函数,以及项列表。

注意:可以定义该函数,以便执行任何可以并行执行的任务。例如,函数可能包含将计算结果写入文件的代码。

那么,为什么我们需要单独的多处理和多线程呢?如果您尝试使用多线程来提高CPU绑定任务的性能,而当进程数超过某个数值时,您可能会注意到,实际上得到的是性能下降。让我们看看为什么会这样。

因为Python也带有全局解释器锁(GIL)。Python会很乐意让用户生成任意数量的线程,但是GIL确保在任何给定的时间只有一个线程执行。

对于一个io绑定的任务,这完全没问题。一个线程向一个URL发出请求,当它等待响应时,可以将该线程替换为向另一个URL发出另一个请求的另一个线程。因为一个线程在收到响应之前不需要做任何事情,所以在给定的时间内只执行一个线程并不重要。

对于CPU绑定的任务,因为一次只执行一个线程,即使生成多个线程,并且每个线程都有自己的数目来检查素数,CPU仍然一次只处理一个线程。实际上,这些数字仍然会被一个接一个地检查。如果在CPU绑定的任务中使用多线程,那么处理多线程的开销将导致性能下降。

为了克服这个“限制”,我们使用了多处理模块。多处理不是使用线程,而是使用多个进程。每个进程都有自己的解释器和内存空间,因此GIL不会阻止任何事情。本质上,每个进程使用不同的CPU内核同时处理不同的数字。

您可能会注意到,与使用简单的for循环,甚至多线程相比,使用多处理时CPU利用率要高得多。这是因为您的程序使用多个CPU内核,而不仅仅是一个内核。

请记住,多处理本身就有管理多个进程的开销,这通常比多线程开销更大。(多处理生成一个单独的解释器,并为每个进程分配一个单独的内存空间)这意味着,根据经验,当可以使用轻量级多线程时,最好使用它(io绑定任务)。当CPU处理成为瓶颈时,通常需要调用多处理模块。但请记住,能力越大,责任越大。

如果一次生成的进程超过CPU的处理能力,您将注意到性能开始下降。这是因为操作系统现在必须做更多的工作来交换CPU内核内外的进程,因为您的进程比内核多。实际情况可能比简单的解释要复杂得多,但这是基本思想。当我们达到16个进程时,您可以看到我的系统性能下降。这是因为我的CPU只有16个逻辑核心。

4,总结

对于io绑定的任务,使用多线程可以提高性能。

对于io绑定的任务,使用多处理也可以提高性能,但是开销往往比使用多线程高。

Python GIL意味着在Python程序的任何给定时间内只能执行线程。

对于CPU绑定的任务,使用多线程实际上会降低性能。

对于CPU绑定的任务,使用多处理可以提高性能。

— — — — — — E N D — — — — — —

往期文章:

Numpy处理tick级别数据技巧

真正赚钱的期权策略曲线是这样的

多品种历史波动率计算

如何实现全市场自动盯盘

AI是怎样看懂研报的

真格量化策略debug秘籍

真格量化对接实盘交易

常见高频交易策略简介

如何用撤单函数改进套利成交

Deque提高处理队列效率

策略编程选Python还是C++

如何用Python继承机制节约代码量

十大机器学习算法

如何调用策略附件数据

如何使用智能单

如何扫描全市场跨月价差

如何筛选策略最适合的品种

活用订单类型规避频繁撤单风险

真格量化回测撮合机制简介

如何调用外部数据

如何处理回测与实盘差别

如何利用趋势必然终结获利

常见量化策略介绍

期权交易“七宗罪”

波动率交易介绍

推高波动率的因素

波动率的预测之道

趋势交易面临挑战

如何构建知识图谱

机器学习就是现代统计学

AI技术在金融行业的应用

如何避免模型过拟合

低延迟交易介绍

架构设计中的编程范式

交易所视角下的套利指令撮合

距离概念与特征识别

气象风险与天气衍生品

设计量化策略的七个“大坑”

云计算在金融行业的应用

机器学习模型评估方法

真格量化制作期权HV-IV价差

另类数据介绍

TensorFlow中的Tensor是什么?

机器学习的经验之谈

用yfinance调用雅虎财经数据

容器技术如何改进交易系统

Python调用C++

如何选择数据库代理

统计套利揭秘

一个Call搅动市场?让我们温习一下波动率策略

如何用真格量化设计持仓排名跟踪策略

还不理解真格量化API设计?我们不妨参考一下CTP平台

理解同步、异步、阻塞与非阻塞

隐波相关系数和偏度——高维风险的守望者

Delta中性还不够?——看看如何设计Gamma中性期权策略

真格量化可访问:

https://quant.pobo.net.cn

真格量化微信公众号,长按关注:

遇到了技术问题?欢迎加入真格量化Python技术交流QQ群  726895887

相关文章

网友评论

    本文标题:Python的多线程和多进程——从一个爬虫任务谈起

    本文链接:https://www.haomeiwen.com/subject/yzbuhctx.html