如题,线上环境使用 thread.start_new_thread 启动了 10 个线程,每个线程读取数据库后,都在往同一个文件里面写入日
志,使用的是 Python 的 logging 模块
运行一段时间后,发现有 2 个线程没有写入日志了,但是其他八个线程仍然正常在写入,htop 查看该线程仍然是存在
的,这是死锁导致的吗?
网上查了下资料,logging 是线程安全的,应该是有 GIL 锁的,但是如果是死锁导致的话,其他八个线程应该也拿不
到锁才对,为什么能够继续写入呢?还是说在查数据库的时候连接超时导致的?
1
linuxchild 2018-09-11 15:21:44 +08:00
看日志吧;
以前试过,日志倒是正常,当时忘记几个线程了 |
2
Buffer2Disk OP @linuxchild 查了日志,也没啥特殊的异常报出来,很奇怪
|
3
Buffer2Disk OP @linuxchild 你当时也是死锁了吗?
|
4
linuxchild 2018-09-11 16:56:50 +08:00
@Buffer2Disk 没,当时日志挺正常的
|
5
Buffer2Disk OP @linuxchild 后来有解决吗?
|
6
colin8102 2018-09-11 17:49:33 +08:00
python 的多线程不是假的么?还会出现打 log 死锁?我都是使用的多进程,通信极其麻烦,
|
7
d18 2018-09-11 17:58:58 +08:00 1
The logging module is intended to be thread-safe without any special work needing to be done by its clients. It achieves this though using threading locks; there is one lock to serialize access to the module ’ s shared data, and each handler also creates a lock to serialize access to its underlying I/O.
文档有写。 |
9
codingcrush 2018-09-11 18:33:32 +08:00
线程安全的
|
10
reself 2018-09-11 18:41:09 +08:00 via Android
建议搞清楚文件锁和 gil 锁的区别。logging 写日志是用 append 模式打开的文件,写入时会加锁。问题在于你的使用方式下这个锁是不是线程安全的?
|
11
lniwn 2018-09-11 19:05:13 +08:00
建议单个日志线程,其他线程把 log 信息都发送到日志线程。
|
12
sampeng 2018-09-11 19:27:46 +08:00
append 还能死锁?长见识。。。
|
13
toono 2018-09-11 19:37:33 +08:00 via iPhone
等待下文
|
14
lolizeppelin 2018-09-11 20:02:01 +08:00 via Android
正常设置下 linux Python 多进城写日志都是安全的
|
15
luzhongqiu 2018-09-11 21:47:38 +08:00
建议,用 async 吧
|
16
justou 2018-09-12 08:33:48 +08:00
做了异常处理没有, 有可能是那两个线程异常退出了
|
17
weyou 2018-09-12 10:15:09 +08:00 via Android
可以看 logging 模块的源码,是做了线程同步的。实际使用中也从未发现有 logging 导致的死锁发生。
|
18
Buffer2Disk OP @justou 异常处理做了,但是只看到了数据库连接超时的日志,超时的话,数据库恢复正常时,会自动重连上去的
线程异常退出的话,不知道怎么样算退出,从 htop 里面看线程还是存在的 |
19
mythmgn 2018-09-12 15:06:44 +08:00
logging 是 thread-safe 的,我们的库在 logging 的基础上实现了 cup.log 模块( https://github.com/baidu/CUP/blob/master/cup/log.py ) ,在线上跑了很久了,没问题的哈。
感觉还是楼主的代码逻辑哪儿有问题导致卡住了,肯定不是 logging 导致的。 |
20
Buffer2Disk OP @mythmgn 我也觉得,如果是 logging 死锁了的话,其他几个线程不会继续正常写入的,
那个线程里面里面就做了 3 件事情 :1.读取远程数据库的数据 2.打印日志 3.开启或者关闭 socket 端口 第一件事情实际测试过,数据库挂掉过几分钟又重新启动后,线程是不会阻塞的,可以继续正常读取数据 打印了异常日志,也没发现什么特别的,就数据库挂掉后,读取超时的日志, 但是现在就出现个玄学问题了,怎么能排查出来问题在哪? |
21
weyou 2018-09-12 19:06:11 +08:00 via Android
@Buffer2Disk 可以检查下线程有没有访问相同的数据资源,比如同一个全局量或同一个对象之类的
|
22
mythmgn 2018-09-12 19:21:19 +08:00
@Buffer2Disk 二分法增加 log 试试。
这样缩小范围到具体是哪儿卡住了。 我调试多线程一般就是靠日志,哈哈。 一般玄学问题大部分都是代码逻辑问题。 真遇到编辑器或者库缺陷的,太少了,除非你直接操作了非常非常底层的东西 |