Python 从业十年是种什么体验?老程序员的一篇万字经验分享( 五 )
<< 26):pass@async_timerasync def coroutine_task:"""异步协程调用"""await asleep(1)@async_timerasync def coroutine_error:"""会抛出异常的协程调用"""raise AttributeError("yo")@async_timerasync def coroutine_main:ioloop = get_event_loopr = await gather(coroutine_task,coroutine_error,ioloop.run_in_executor(thread_executor, io_blocking_task),ioloop.run_in_executor(process_executor, cpu_blocking_task),return_exceptions=True,)logger.info(f"coroutine_main got {r}")@timerdef main:get_event_loop.run_until_complete(coroutine_main)if __name__ == "__main__":main学到这一步 , 你已经能够熟练的运用协程、线程、进程处理不同类型的任务 。 接着拿上面提到的垃圾 4 核虚机举例 , 你现在应该可以比较轻松的实现达到 1k QPS 的服务 , 在白天十小时里可以处理超过一亿请求 , 费用依然仅 20元/天 。 你还有什么借口说是因为 Python 慢呢?
人们在聊到语言/框架/工具性能时 , 考虑的是“当程序员尽可能的优化后 , 工具性能会成为最终的瓶颈 , 所以我们一定要选一个最快的” 。
但事实上是 , 程序员本身才是性能的最大瓶颈 , 而工具真正体现出来的价值 , 是在程序员很烂时 , 所能提供的兜底性能 。
如果你觉得自己并不是那个瓶颈 , 那也没必要来听我讲了
在性能优化上有两句老话:
- 一定要针对瓶颈做优化
- 过早优化是万恶之源
成长的空间很大 , 多在自己身上找原因 。
一个经验观察 , 即使在工作中不断的实际练习 , 对于异步协程这种全新的思维模式 , 从学会到能在工作中熟练运用且不犯大错 , 比较聪明的人也需要一个月 。
换成 go 也不会好很多 , await 也能实现同步写法 , 而且你依然需要面对我前文提到过的同步控制和资源用量两个核心问题 。
简单提一下性能分析 , py 可以利用 cProfile、line_profiler、memory_profiler、vprof、objgraph 等工具生成耗时、内存占用、调用关系图、火焰图等 。
关于性能分析领域的更多方法论和理念 , 推荐阅读《性能之巅》(过去做的关于性能之巅的部分摘抄 ) 。
必须强调:优化必须要有足够的数据支撑 , 包括优化前和优化后 。
性能优化其实是一个非常复杂的领域 , 虽然上面提到的工具可以生成各式各样的看上去就很厉害的图 , 但是优化不是简单的你看哪慢就去改哪 , 而是需要有极其扎实的基础知识和全局思维的 。
而且 , 上述工具得出的指标 , 在性能尚未逼近极限时 , 可能会有相当大的误导性 , 使用的时候也要小心 。
有一些较为普适的经验:
- I/O 越少越好 , 尽量在内存里完成
- 内存分配越少越好 , 尽量复用
- 变量尽可能少 , gc 友好
- 尽量提高局部性
- 尽量用内建函数 , 不要轻率造轮子
- 循环展开
- 内存对齐
- zero copy(mmap、sendfile)
最常见的划分可以称之为黑盒 & 白盒 , 前者是只针对接口行为的测试 , 后者是深入了解实现细节 , 针对实现方式进行的针对性测试 。
对 Py 开发者而言 , 最简单实用的工具就是 unitest.TestCase 和 pytest , 在包内任何以 test*.py 命名的文件 , 内含 TestCase 类的以 test* 命名的方法都会被执行 。
测试方法也很简单 , 你给定入参 , 然后调用想要测试的函数 , 然后检查其返回是否符合需求 , 不符合就抛出异常 。
"""test_demo.py"""from unittest import TestCasefrom typing import Listdef demo(l: List[int]) -> int:return l[0]class DemoTestCase(TestCase):def setUp(self):print("first run")def tearDown(self):print("last run")def test_demo(self):data = http://kandian.youth.cn/index/self.assertRaises(IndexError, demo, data)
文章插图
开始写测试后 , 你才会意识到你的很多函数非常难以测试 。 因为它们可能有嵌套调用 , 可能有内含状态 , 可能有外部依赖等等 。
但是需要强调的是 , 这不但不是不写测试的理由 , 这其实正是写测试的目的!
- 丹丹|福佑卡车创始人兼CEO单丹丹:数字领航 驶向下一个十年
- 爱奇艺|连续亏损十年,爱奇艺收入不及快手,视频网站的出口在哪里?
- 直播从业者|高三老师监考时开直播,面对质疑还振振有词,怕困没有打扰学生
- 付费|谁在定义未来三十年?音频内容付费,60后人数同比增154%,00后增94%
- 悬空|华为Mate悲壮史十年逆袭,三轮打压,一朝悬空
- 告诉|阿里大佬告诉你如何一分钟利用Python在家告别会员看电影
- Python源码阅读-基础1
- Python调用时使用*和**
- 如何基于Python实现自动化控制鼠标和键盘操作
- 解决多版本的python冲突问题