那段时间一直在写脚本,脑子里反复在想单线程和多线程哪个好,网上各种各样的说法混在一起,越看越拿不定主意。手上的任务很简单,就是遍历一个文件夹里几百个文本,把里面的内容提取出来整理成表格,最开始直接顺着思路写,一行接一行往下跑,也就是单线程。
跑起来的时候,屏幕上就只有一行日志慢慢滚动,读完一个文件才会去碰下一个。电脑别的地方还能正常点,浏览器网页切换也不卡,就是这个脚本的进度走得很慢,盯着那个进度条,等了快二十分钟才跑完全部。当时心里就在琢磨,换成多线程会不会快很多,别人都说多线程可以同时干好几件事,应该能省下不少等待的时间。
改代码花了一个傍晚,把读取文件的部分拆出去,开了线程池来跑。按下运行键的那一刻,日志一下子噼里啪啦往外蹦,速度看着明显上来了,心里还松了口气,觉得这次总算选对路子了。
没一会问题就冒出来。
有些文件读取出来的内容乱掉了,写入表格的时候,好几段文字挤在了同一行,顺序完全错开。还有几次,程序直接卡住不动,没有报错,就安安静静停在那里,要手动关掉进程重新启动。一开始以为是代码哪里写错了,反复调整参数,一会调大线程数量,一会又缩小,来回试了好多次,情况时好时坏,有时候跑一半崩掉,有时候勉强跑完,但是导出的表格里面有一部分记录是错位的,没法直接拿来用。
后来才反应过来,不是多线程本身不行,是我要往同一个表格里写数据,多个线程同时去操作同一个文件,很容易互相抢资源,信息就串在一起了。那个时候也没有去加锁,只是单纯想着加快读取的速度,忽略了后面写入的环节。试着分开处理,读取用多线程,收集完所有结果之后,再用单线程统一写入,改动之后,乱序的情况少了很多,可新的麻烦又出现,开太多线程的时候,磁盘的读取压力上去,系统的响应反而变钝,别的软件打开都变得迟缓。
找朋友聊这件事,他做的是接口请求类的脚本,一直用多线程,说对他来说效率提升很明显,等待响应的空档可以安排别的任务,不会白白耗着。他听完我遇到的状况,也说文件读写这类场景,不一定线程开得越多就越顺,要看硬件和读写的目标。
来回切换两种写法试了好几天,没有一个能让我觉得完美的方案。单线程稳,出来的数据不会乱,不用花时间去核对错位的内容,就是耗时长,等待的过程磨人。多线程在合适的配置下速度会快一截,但是要额外处理同步、冲突这些东西,一旦考虑不周,产出的数据就没法直接使用,后面核对修正的时间,有时候比直接用单线程跑完还要久。
只代表我这一次处理文本提取的经历,换别的任务,感受大概率会不一样。
最后没再执着于非要分出高下,就固定用读取多线程、写入单线程的方式继续跑,不去盲目拉高线程数。那天晚上关掉编辑器,桌面上放着两份导出的表格,一份是单线程慢慢跑出来的干净版本,一份是多线程跑出来、还留着几行错位文字的版本。
关掉电脑的时候,没有去想以后优先选哪一种,只是不想再对着帖子里的结论纠结。
第二天打开电脑,第一件事是给脚本加了一段日志记录,把每一个文件的读取顺序单独记下来。
我只是不想再分不清哪条记录是哪一个文件里的。
这件事到最后,我也没有得到一个可以直接拿来套用的答案。
只是记住了,快,不代表省心。