Random Posts
Tags
Categories
Recent Comments
- 小肥 on GDB 从裸奔到穿戴整齐
- flandre on 异步事件模型的 Self-pipe trick
- inv on 异步事件模型的 Self-pipe trick
- skywind on 异步事件模型的 Self-pipe trick
- skywind on 异步事件模型的 Self-pipe trick
Links
Meta
Category Archives: 编程技术
库代码中是否应该检查 malloc 的返回值?
现在网上有很多似是而非的观点,比如 malloc 失败不用处理,直接退出,这样的经验看似很聪明,实际却很局限,比如: 1)嵌入式设备:不是所有设备都能有一个强大的全功能的操作系统,也不是所有设备都能有虚拟内存功能。 2)长时间运行的程序,内存虽然够,但由于碎片,会导致没有连续足够大的线性地址进而分配失败,32 位程序特别明显。 3)管理员对某类进程设置过内存限制,比如某类要起很多个的进程,那么设置一下内存限制是一个很正常的操作。 4)程序通过容器运行,事先给定了最大内存用量。 5)操作系统 overcommit 选项被管理员关闭。 所以说 malloc 失败不用检测,大多数是明确知道自己运行环境的某一类程序,比如上层业务,比如 CRUD,比如你就是做个增删改查,知道自己运行于一台标准的 linux 服务器,那么确实无需多处理,崩了也就崩了;或者你的程序严重依赖 malloc 三行代码一次分配,那么即使恢复出来估计你也很难往下走,不如乘早崩溃,免得祸害他人。 上面这些情况确实可以简单粗暴处理,但如果你开发一些基础库,你没办法决定自己是会运行在一台标准服务器上还是某个小设备里,那么上面的经验就完全失效了。 比如你开发一个类似 libjpeg 的图象编解码库,你没法假定运行环境,那么 malloc 失败时,你是该自作主张直接 assert 强退掉呢?还是该先把分配了一半的各种资源释放干净,然后向上层返回错误码,由上层决定怎么处理比较好呢?比如上层可选择:1)报错退出;2)释放部分缓存后再运行;3)降级运行,比如图象编码使用 low profile 再运行一遍。 你作为图象编码库需要经常分配一些比较大块的内存,你这里失败了,不代表上层无法继续分配内存处理后续任务对不对?上层内存里有很多图片 cache 用于加速图片显示,你这里失败了,上层感知到,直接从 cache 里回收一波,内存就又有了,对不对?图象视频编码根据资源消耗高低都有 high profile, low profile 的运行模式,你 … Continue reading
性能测试:asyncio vs gevent vs native epoll
测试一下 python 的 asyncio 和 gevent 的性能,再和同等 C 程序对比一下,先安装依赖: pip3 install hiredis gevent 如果是 Linux 的话,可以选择安装 uvloop 的包,可以测试加速 asyncio 的效果。 测试程序:echo_bench_gevent.py import sys import gevent import gevent.monkey import hiredis from gevent.server import StreamServer gevent.monkey.patch_all() d = {} def process(req): # … Continue reading
别被忽悠了 Lua 数组真的也可以从 0 开始索引?
先前我说 Lua 数组从 1 开始不太爽,很多人来纠正我说也可以从 0 开始,比如: local m = { [0] = 100, 101, 102, 103 } 然后访问时 m[0] 也可以正常访问到第 0 个元素,所以 “Lua 给你充分自由度,让你可以从任意下标索引数组”,貌似好像说的很有道理,但是不是这样呢? 我们先用 # 符号打印下上面数组的长度: print(‘size’, #m) 输出是:3 ,而不是实际元素个数 4,因为 # 就是从 1 开始数起的,所以如果你代码里用了 m[0] ,你也需要额外方式计算长度,同时保证用到这个数组的其他代码也遵从这样计算。 还有一个问题,使用 … Continue reading
为什么 C 语言数组是从 0 开始计数的?
C 语言等大多数编程语言的数组从 0 开始而不从 1 开始,有两个原因: 第一:地址计算更方便 C 语言从 0 开始的话,array[i] 的地址就正好是: (array + i) 如果是从 1 开始的话,就是 (array + i – 1) 多一次计算,性能受影响,再扩展到二维数组的话 array[i][j] 从 0 开始的地址是: (array + i * N + j) 多整洁,而从 1 开始要变成 (array + … Continue reading
用 Lazarus 做界面合适吗?
也许你没留意,很多你经常用的桌面软件是用 Lazarus 开发的。 作为 Delphi 的开源替代品,我一直是比较喜欢 Lazarus 的,虽然有些小众。技术有两种,有些是用来挣钱养家,用来赶进度大规模集团作战的;还有一类是出于兴趣,单纯觉得好玩,会不自觉的有空就翻出来当爱好的,比如 Lazarus 就是一个很好玩的玩具。 因此不用成天纠结 “谁是 GUI 天下第一” 之类内卷的问题,抱着轻松和评测+鉴赏的心情了解下或许也不错。 在此之前,得先说两句 Delphi,姚冬老师,知乎编程板块无人不知,给了 Delphi 这样的评价: Delphi 是神作,它在 RAD(快速应用开发)领域长时间没有对手,直到BS架构取代CS架构。Delphi 的特点就是简单、开发快,单纯就写个基本可用的应用来说,可能至今都没有比他更快的。 为啥作为国内最早使用 Qt 的人,却会给 Delphi 那么高的评价呢?中小应用开发 “至今没有比他更快的技术”这么高的评价,必然是有原因的,无独有偶,另一位 Qt 大神也发表示过对 Delphi 继承者 Lazarus 的喜爱: Delphi 的继承人有两个,第一个是 C# Winform,几乎是把 Delphi … Continue reading
给 Qt5 引入 C# / Delphi 的 Anchor Layout
在前文 用 MFC 写 GUI 程序是一种什么样的体验? 中提过 Anchor Layout 可以很简单的设定让控件跟随窗口四条边大小变化的策略: 比如右下角的两个按钮,设置的 anchor 是 “right,bottom” 他们在窗口扩大缩小时,会跟右和下两条边保持恒定距离,左上角的文字是 “left,top” 的 anchor,他会保持恒定的左边距和上边距,中间文字框的 anchor 是四个方向的 “left,top,right,bottom” 他会和窗口四条边框保持相同边距,因此会随窗口扩大而扩大。 这种布局方式最早是 Delphi / C++ Builder 引入的,非常简单实用,后来被 C# Winform 原封不动的抄了过去,而 QtWidgets 里用了另一套规则,虽然用起来更精细了,却没有 anchor layout 这么简单直白。 虽然 QtQuick 和 QGraphicsItem … Continue reading
用 MFC 写 GUI 程序是一种什么样的体验?
本文来自知乎问题:MFC、WTL、WPF、wxWidgets、Qt、GTK 各有什么特点? 感觉我说了太多 Qt 的事情了,今天只说一下 MFC ,到底过时在哪里,都在说 “MFC 就是 xxx” 类似的话,我来补充点细节,增加点感性认识,到底 MFC 过时在哪里?想要用好 MFC 可以怎么办? 虽然 MFC 也有 DIALOG 的设计器,似乎可以拖一下控件,做个 hello world, 计算器之类的好像也很简单,但是稍微复杂那么一点就麻烦了,比如布局,MFC 里的控件只能设置绝对坐标和大小,那么如果你的窗口扩大或者缩小了,想自动改变内部特定控件的大小和位置怎么办?比如 C# 里随便设置一下各个控件的 docking 和 anchor 就能: C# 里给控件设置 docking/anchor:窗口变大变小后就能自动调整控件的位置和大小 就能让某些控件随窗口变大而移动,某些控件随窗口变大而变大,而某些控件不变,这在任何 GUI 库里都是最基础的功能,都可以在设计器里点两下就做到的事情,MFC 却需要重载 WM_SIZE, WM_SIZING 消息来自己写代码每次手工计算所有控件的新坐标和大小,想写的通用点,还得上千行的代码,枚举所有子控件,根据额外信息重新计算位置大小,虽然 … Continue reading
怎么样打包 pyqt 应用才是最佳方案?
早先看一堆人说 PyQt 打包麻烦,部署困难的,打出来的包大(几十兆起步),而且启动贼慢,其实 Python+PyQt 打包非常容易,根本不需要用什么 PyInstaller,我手工打包出来的纯 Python 环境只有 5MB,加上 PyQt 也才 14MB。 很多人用 PyInstaller 喜欢加一个 -F 参数,打包成一个单文件: 这样的单文件看起来似乎很爽,其实他们不知道,这其实是一个自解压程序,每次运行时需要把自己解压到 temp 目录,然后再去用实际的方式运行一遍解压出来的东西: Process Explorer 把雷达图标拖动到 pyqt_hello.exe 的窗口上,可以看到有两个 pyqt_hello.exe 的文件,外面那个是你打包出来的,里面那个才是真正的程序(虽然可执行都是一个),看看它下面依赖的 python310.dll 是在哪里?这不就是一个临时解压出来的目录么: 看到没?这就是你 PyInstaller 打包出来的 30MB 的程序,每次运行都要临时解压出 71MB 的文件,运行完又删除了,那么如果打包出来的可执行有 100MB,每次运行都要释放出 200-300 MB 的东西出来,所以为什么 … Continue reading