专栏首页专注网络研发Python与Golang的网络IO性能对比

Python与Golang的网络IO性能对比

近期,在做未来服务端新业务的技术语言选型。之前我们的服务端都是使用C++开发,充分榨干了服务器的系统资源 —— 创业公司嘛,服务器也是不小的开销,能节省就节省一点吧。后面考虑到要快速的开发新业务,可能需要使用更高级语言。

在高级语言中,我比较倾心Golang,并不是因为其是google出品,而是因为其下面的三个特点。

一、Golang既可以像高级脚本语言快速开发,又有编译型语言静态检查的优点,避免在运行时出现非期望的错误。

以前用python写过一个数据分析程序,由于数据量很大,在已经运行了几个小时之后,遇到一个非期望的类型,进入了错误处理,这些我都考虑到了。但没想到的是,在错误处理中,有个拼写错误(忘了是函数,还是变量了),导致python抛出来了一个未捕获的异常,运行几个小时的结果直接消失了。这是我对python最不爽的地方。—— 有多少人能保证做单元测试时,能做到100%覆盖,尤其是错误处理的代码。而使用Golang则完全不用担心这个问题,其语法检查在某些点,甚至比C/C++要求的还要严格。

二、Golang的goroutine确实用起来很方便,极大的降低了并行开发的难度。

对于开发者来说,无需设计线程模型,甚至都不用调用线程,一句简单的go语句就直接实现了并行处理。至于Golang是如何操作的,对调用者完全透明。至于性能,让我们直接信任Golang的实现。当然,如果追求接近C++的性能要求,还是要开发者做些处理的。后面可以通过测试程序,了解goroutine的性能。

三、Golang有强制的Coding Style和格式化工具

Coding Style跟讨论哪个语言最好一样,总会引起开发人员无谓的争吵。尤其在某些细微的地方,其实无所谓高低上下,但是对于团队来说,就是喜欢争个面红口赤。我自己对各种Coding Style没有什么倾向,只要是统一的标准就行,使用Golang的强制style和格式化工具,节约大家的时间。

使用高级语言保证了开发速度,但性能也不能太低。比如Python,因为其GIL的限制,我一直对于使用Python实现服务程序持保留意见。我一般只用Python写一些工具,测试脚本等。并且,由于上面所说Python缺少静态检查,在运行中容易出现非期望的错误,影响服务的稳定性。

下面进入今天的正题,“网络IO性能测试”。我选择了C++、Python和Golang进行对比,测试其网络IO性能。测试代码位于:https://github.com/gfreewind/test_cases/tree/master/script_perf/NetIO

测试脚本位于:https://github.com/gfreewind/test_cases/blob/master/script_perf/NetIO/test_script/test_new_conn.sh

使用http_load每秒产生指定数量的TCP连接,并发送HTTP请求,接收回应。

一、C++

没有做特别的优化,但代码量仍然比高级语言多出不少。此处不罗列代码,仅简单说明设计。使用对等的worker线程模型,每个线程绑定到不同的CPU上,利用REUSEADDR和REUSEPORT创建自己的监听套接字,由内核进行流量负载。IO模型使用epoll进行多路复用,同步接收和发送数据。这样的设计,基本上可以实现水平扩展,随着CPU核心数增加,性能也线性上升。

测试结果:一个线程(一个core)支持20K+ RPS,并可以水平扩展。

二、Python

由于Python的GIL限制,为了充分保证多核并发,真正部署时应该会采用多进程的方式。所以这个测试程序,只使用一个线程,IO模型也是使用epoll多路复用,同步接收和发送数据。

测试结果:一个进程支持11K+ RPS左右。

我的Python水平大概是入门水准,写这个测试程序大约用了半小时左右,比写C++要快很多了,但性能只是C++的一半左右。不知道Python高手是否还可以进一步优化这个Python程序,来提高性能。

三、Golang

既然使用了Golang,自然要用Goroutine来做并行处理。所以这个IO模型是每个新建连接,创建一个goroutine进行同步接收和发送。但为了公平,使用taskset限制Golang测试程序只能运行在一个核心上。

测试结果:一个核心支持16K+ RPS

我的Golang水准是绝对的初学者,但写这个测试程序,也只花了不到半小时(跟Python差不多)。在这个测试程序中,每个新建连接,都粗暴的创建一个goroutine处理,没想到性能还可以。但这样的设计,并不能像C++那样水平扩展,无法随核心数目增加而线性提高性能。比如运行这个Golang程序运行在2个核心时,其性能只提高到22K+ RPS左右。如果要重分利用多核,还要做更好的设计,或者也像Python那样简单使用多进程部署。

不过Golang对标的是Python,都是使用一个核心,Golang的性能完善Python。当然,有的人也许会说,那是因为Golang使用了Goroutine,而Python是单线程处理。没错,但Python要像Golang这样每个连接创建一个线程,性能也好不到哪去。如果要做成线程池,那开发时间,不大可能在半小时内完成。(Python3好像支持协程了,这个我没有试过,熟悉的同学可以测试一下。据说,不如Goroutine方便自然)

综合开发速度、难度、性能、以及稳定性,就我而言,我认为Golang要完胜Python。Python虽然有各种丰富的库资源,但对于服务程序来说,Golang的资源也能满足大部分需求了。我愿意让团队在后面的工作中,尝试使用Golang开发服务程序,而继续使用Python来做工具和测试:D

PS:这是测试结果链接https://github.com/gfreewind/test_cases/blob/master/script_perf/NetIO/RESULT.txt

本文分享自微信公众号 - LinuxerPub(LinuxerPub),作者:glinuxer

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-06-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux内核那些事之连接跟踪

    连接跟踪(也叫会话管理)是状态防火墙关键核心,也是很多网元设备必不可少的一部分。各厂商的实现原理基本雷同,只是根据各自的业务进行修改和优化。其中,还有不少厂商干...

    glinuxer
  • TCP的MTU Probe和MSS(2)

    在上一篇《TCP的MTU Probe和MSS(1)》介绍了TCP使用MTU Probe来避免PMTU变小而导致发送失败的方法。其主要思想是在TC...

    glinuxer
  • TCP的定时器实现(1)——重传定时器

    TCP协议是一个相当复杂的协议,其实现依赖于多个定时器的实现。在TCP套接字的初始化函数tcp_v4_init_sock中,会调用tcp_init_xmit_t...

    glinuxer
  • JSP 常用语法

    Remember_Ray
  • JSP 常用语法

    Remember_Ray
  • Keras 的 Web 填坑记

    博客主页:https://www.zhihu.com/people/tu-dou-dou-27-10

    Python中文社区
  • Python C API的使用详解(一)

    介绍一下Python虚拟机的初始化及退出,Python基本数据类型的对象创建以及C和Python之间的数据类型互相转换。

    py3study
  • 时讯| 影创科技Halomini首批产品正式交付

    VRPinea
  • Vue2+VueRouter2+Webpack+Axios 构建项目实战2017重制版(十一)阶段性小结

    Vue2+VueRouter2+Webpack+Axios 构建项目实战2017重制版(十一)阶段性小结 前情回顾 去年写的那一套东西,虽然我也写得非常的认真,...

    FungLeo
  • 600+英语绘本、500+英语儿歌 腾讯ABCmouse免费开放海量学习资源

    ? 停课期间,为助力孩子们在家也能随时随地开启英语启蒙。腾讯ABCmouse宣布,疫情期间将免费开放ABCmouse在线英语启蒙课里的五大学习区,包括600+...

    鹅老师

扫码关注云+社区

领取腾讯云代金券