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

论坛 期权论坛 期权     
真格量化   2019-6-28 09:54   2499   0
本文的目的是解释为什么在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++
如何选择数据库代理
统计套利揭秘
[h1]一个Call搅动市场?让我们温习一下波动率策略[/h1][h1]如何用真格量化设计持仓排名跟踪策略[/h1][h1]还不理解真格量化API设计?我们不妨参考一下CTP平台[/h1][h1]理解同步、异步、阻塞与非阻塞[/h1][h1]隐波相关系数和偏度——高维风险的守望者[/url][/h1][url=http://mp.weixin.qq.com/s?__biz=MzU4OTg0NjkyOA==&mid=2247484107&idx=1&sn=e7eafaf7f98160bc6c9f3bc03b6428f9&chksm=fdc60234cab18b229bfbcfae8bc67ce5072004f8bdd1736c8e00d0edd9bb449029de68f6659f&scene=21#wechat_redirect]Delta中性还不够?——看看如何设计Gamma中性期权策略



真格量化可访问:
https://quant.pobo.net.cn


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

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













分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:870
帖子:180
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP