什么是“零拷贝”技术

论坛 期权论坛 期权     
真格量化   2019-10-28 09:05   7997   0
高频交易的研究者有时会遇到“零拷贝”(zero-copy)技术这个名词,那么什么是“零拷贝”呢?
一般的文件传输过程



考虑这样一种常用的情形:开发者需要将静态内容(类似图片、数据表、文件)展示给远程的用户。那么这个情形就意味着开发者需要先将静态内容从磁盘中拷贝出来放到一个内存buf中,然后将这个buf通过socket传输给用户,进而用户或者静态内容的展示。这看起来再正常不过了,但是实际上这是很低效的流程,我们把上面的这种情形抽象成下面的过程:

首先调用read将静态内容,这里假设为数据文件A,读取到tmp_buf, 然后调用write将tmp_buf写入到socket中,如图:

在这个过程中数据文件A的经历了4次复制的过程:


  • 首先,调用read时,数据文件A拷贝到了kernel模式;


  • 之后,CPU控制将kernel模式数据复制到user模式下;


  • 调用write时,先将user模式下的内容复制到到kernel模式下的socket的buffer中;


  • 最后将kernel模式下的socket buffer的数据复制到网卡设备中传送;


从上面的过程可以看出,数据白白从kernel模式到user模式走了一圈,浪费了2次copy(第一次,从kernel模式拷贝到user模式;第二次从user模式再拷贝回kernel模式,即上面4次过程的第2和3步骤)。而且上面的过程中kernel和user模式的上下文的切换也是4次。


幸运的是,开发者可以用“零拷贝”技术来去掉这些无谓的复制。应用程序用Zero-Copy来请求kernel直接把disk的data传输给socket,而不是通过应用程序传输。Zero-Copy大大提高了应用程序的性能,并且减少了kernel和user模式上下文的切换。


Linux中的零拷贝


例如,在 Linux 中,减少拷贝次数的一种方法是调用 mmap() 来代替调用 read,比如:





首先,应用程序调用了 mmap() 之后,数据会先通过 DMA 被复制到操作系统内核的缓冲区中去。接着,应用程序跟操作系统共享这个缓冲区,这样,操作系统内核和应用程序存储空间就不需要再进行任何的数据复制操作。应用程序调用了 write() 之后,操作系统内核将数据从原来的内核缓冲区中复制到与 socket 相关的内核缓冲区中。接下来,数据从内核 socket 缓冲区复制到协议引擎中去,这是第三次数据拷贝操作。



通过使用 mmap() 来代替 read(), 已经可以减半操作系统需要进行数据拷贝的次数。当大量数据需要传输的时候,这样做就会有一个比较好的效率。但是,这种改进也是需要代价的,使用 mma()p 其实是存在潜在的问题的。当对文件进行了内存映射,然后调用 write() 系统调用,如果此时其他的进程截断了这个文件,那么 write() 系统调用将会被总线错误信号 SIGBUS 中断,因为此时正在执行的是一个错误的存储访问。这个信号将会导致进程被杀死,解决这个问题可以通过以下这两种方法:


为 SIGBUS 安装一个新的信号处理器,这样,write() 系统调用在它被中断之前就返回已经写入的字节数目,errno 会被设置成 success。但是这种方法也有其缺点,它不能反映出产生这个问题的根源所在,因为 BIGBUS 信号只是显示某进程发生了一些很严重的错误。


第二种方法是通过文件租借锁来解决这个问题的,这种方法相对来说更好一些。我们可以通过内核对文件加读或者写的租借锁,当另外一个进程尝试对用户正在进行传输的文件进行截断的时候,内核会发送给用户一个实时信号:RT_SIGNAL_LEASE 信号,这个信号会告诉用户内核破坏了用户加在那个文件上的写或者读租借锁,那么 write() 系统调用则会被中断,并且进程会被 SIGBUS 信号杀死,返回值则是中断前写的字节数,errno 也会被设置为 success。文件租借锁需要在对文件进行内存映射之前设置。


使用 mmap 是 POSIX 兼容的,但是使用 mmap 并不一定能获得理想的数据传输性能。数据传输的过程中仍然需要一次 CPU 复制操作,而且映射操作也是一个开销很大的虚拟存储操作,这种操作需要通过更改页表以及冲刷 TLB (使得 TLB 的内容无效)来维持存储的一致性。但是,因为映射通常适用于较大范围,所以对于相同长度的数据来说,映射所带来的开销远远低于 CPU 拷贝所带来的开销。


sendfile()


为了简化用户接口,同时还要继续保留 mmap()/write() 技术的优点:减少 CPU 的复制次数,Linux 在版本 2.1 中引入了 sendfile() 这个系统调用。


sendfile() 不仅减少了数据复制操作,它也减少了上下文切换。首先:sendfile() 系统调用利用 DMA 引擎将文件中的数据复制到操作系统内核缓冲区中,然后数据被复制到与 socket 相关的内核缓冲区中去。接下来,DMA 引擎将数据从内核 socket 缓冲区中复制到协议引擎中去。如果在用户调用 sendfile () 系统调用进行数据传输的过程中有其他进程截断了该文件,那么 sendfile () 系统调用会简单地返回给用户应用程序中断前所传输的字节数,errno 会被设置为 success。如果在调用 sendfile() 之前操作系统对文件加上了租借锁,那么 sendfile() 的操作和返回状态将会和 mmap()/write () 一样。

sendfile() 系统调用不需要将数据拷贝或者映射到应用程序地址空间中去,所以 sendfile() 只是适用于应用程序地址空间不需要对所访问数据进行处理的情况。相对于 mmap() 方法来说,因为 sendfile 传输的数据没有越过用户应用程序 / 操作系统内核的边界线,所以 sendfile () 也极大地减少了存储管理的开销。但是,sendfile () 也有很多局限性,如下所列:


sendfile() 局限于基于文件服务的网络应用程序,比如 web 服务器。据说,在 Linux 内核中实现 sendfile() 只是为了在其他平台上使用 sendfile() 的 Apache 程序。


由于网络传输具有异步性,很难在 sendfile () 系统调用的接收端进行配对的实现方式,所以数据传输的接收端一般没有用到这种技术。


基于性能的考虑来说,sendfile () 仍然需要有一次从文件到 socket 缓冲区的 CPU 复制操作,这就导致页缓存有可能会被传输的数据所污染。


Python对“零拷贝”的支持


自从Python 3.3中sendfile系统调用可用作os.sendfile,python 3.5 为基于socket的应用带来了更高级的封装包socket.socket.sendfile。


例如通过socket.socket.sendfile来改进大尺寸文件的传输速度:



在100次大尺寸文件(4GB数据文件)传输测试中,和不使用零拷贝技术的sock.recv相比,使用零拷贝技术的socket.sendfile可以减少一半的时间且显著提高文件传输的稳定性(降低传输时间的标准差)。对于需要大量传输数据的量化交易应用,这一技术也能改善交易系统的性能。





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



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


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

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






往期文章:
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]隐波相关系数和偏度——高维风险的守望者[/h1]Delta中性还不够?——看看如何设计Gamma中性期权策略

[h1]Python的多线程和多进程——从一个爬虫任务谈起[/h1]线程与进程的区别
皮尔逊相关系数与历史K线匹配

Python2和Python3的兼容写法
Python代码优化技巧

理解Python的上下文管理器

如何写出更好的Python代码?这是Python软件基金会的建议
评估程序化模型时我们容易忽视的指标

看看如何定位Python程序性能瓶颈

什么是Python的GIL

投资研究中的大数据分析趋势及应用

理解CTP中的回调函数

如何围绕隐含波动率设计期权交易策略                    
看看如何用Python进行英文文本的情感分析
算法交易的分类

Python编码的最佳实践总结

什么是波动率锥?如何用波动率锥设计期权策略?
期权的波动率策略与时间价值收集策略对比

期权用于套期保值和无风险套利

隐含波动率对期权策略的影响

卖出期权交易的风险管理原则和技巧
期权交易中的“大头针”风险
期权做市商策略简介

精细化您的交易——交易成本评估与交易执行策略
海外市场交易执行策略的实践
设计期权套期保值方案时应注意的问题
美式期权、欧式期权比较分析——定价与风险管理
构建您的AI时代武器库——常用的机器学习相关Python库
期权波动率“微笑曲线”之谜
运算任务愈发繁重,如何加速Python程序运行?
证券市场微观结构理论模型是什么

是瞬间成交还是漫长等待?——如何衡量市场流动性
波动率指数及其衍生品介绍

Python的异常处理技巧

Python中的阻塞、异步与协程

"香草"之外的更多选择——几种常见的路径依赖奇异期权
什么是CTP?——了解上期所CTP快速交易系统
了解季节性——以谷物和油籽为例
是前因还是后果?——在真格量化中进行格兰杰因果检验

Python导入模块的技巧
Python程序员常犯的十个错误

搜索数据泄露天机?——舆情指数与期货行情关联性分析思路

机器学习常见算法分类汇总

如何使用Data Pipeline 自动化数据处理工作?
CTP API的委托介绍和在真格量化中的订单流控制
高频交易对市场的影响
期货行情及其组织形式——以上期所为例
理解并行与并发
郑商所和大商所套利指令及在真格量化的实现
机器学习用于金融市场预测面临的挑战
高频交易中风险控制的常用措施
查询结果偏离预期?来了解CTP的报单函数及委托状态查询
Python中的ftplib模块

理解真格量化的Python编程范式
需要处理大量市场数据?来了解一下MySQL、HBase、ES的特点和应用场景

NumPy中的ndarray与Pandas的Series和DataFrame之间的区别与转换
Python中的scikit-learn机器学习功能库
什么是程序设计中的高内聚、低耦合?
Python的内存管理与垃圾回收机制
云服务中的容器技术
什么是“面向对象”程序设计-以Python为例
波动率介绍及其在资产定价中的应用
发现策略中的孪生兄弟——期权交易中的等价或相似策略解析

如何利用期权改进指数投资表现——借鉴海外市场经验
如何用期权进行“哑铃型”资产配置——“90/10”策略介绍
国外著名商品指数编制方法比较
FPGA技术在金融行业的应用——以沪深行情加速为例
美国市场对部分高频交易行为的监管

报价驱动制度与指令驱动制度比较
理解动量投资策略和逆向投资策略——通过行为金融学视角

期权做市商面临的风险及其对做市业务的影响

商品期权在现货企业中的应用
期权进行套期保值的优势与策略分类

COT报告揭秘——如何解读CFTC的持仓报告[url=http://mp.weixin.qq.com/s?__biz=MzU4OTg0NjkyOA==&mid=2247484604&idx=1&sn=1b4b91dbc0736878a4ed6d68fa24f0dd&chksm=fdc60443cab18d558789d8fd74634000456e521f34fc62c7e416ef1b7a9dc6e73c97ef7e7d53&token=600122763&lang=zh_CN&scene=21#wechat_redirect][/url]
























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

本版积分规则

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

下载期权论坛手机APP