Python: os.read() / os.write() 在 os.pipe() 上线程安全吗?
考虑一下:
pipe_read, pipe_write = os.pipe()
现在,我想知道两件事:
(1) 我有两个线程。如果我保证只有一个线程在读取 os.read(pipe_read,n)
,而另一个线程只在写入 os.write(pipe_write)
,那么即使这两个线程同时进行,我会遇到什么问题吗?我能否按正确的顺序获取所有写入的数据?如果它们同时进行,会发生什么?是否有可能一次写入的数据被分成几部分读取,比如:
Thread 1: os.write(pipe_write, '1234567')
Thread 2: os.read(pipe_read,big_number) --> '123'
Thread 2: os.read(pipe_read,big_number) --> '4567'
或者——再考虑一下同时进行——一次 os.write(some_string)
是否总是会通过一次 os.read(pipe_read, very_big_number)
完整返回?
(2) 考虑多个线程使用 logging.handlers.FileHandler()
向管道的 pipe_write
端写入——我读过日志模块是线程安全的。这是否意味着我可以这样做而不会丢失数据?我认为我无法控制管道中数据的顺序;但这并不是一个要求。
要求:
- 所有由某些线程在写入端写入的数据必须在读取端出来
- 由单个
logger.info(), logger.error(), ...
写入的字符串必须保持完整。
这些要求能满足吗?
提前感谢,
Jan-Philip Gehrcke
1 个回答
os.read
和 os.write
在通过 os.pipe
得到的两个文件描述符上是线程安全的,但你似乎想要的不止这些。关于 (1)
,是的,单次读取或写入并没有“原子性”保证——你描述的场景(一次短写入结果变成两次读取)是完全可能的。一般来说,os.whatever 只是对操作系统功能的一个简单封装,具体的功能是否能满足你的需求,还是要看操作系统本身;在这个情况下,Posix 标准并不要求操作系统保证这种“原子性”。你可以保证获取到所有写入的数据,并且顺序是正确的,但仅此而已。一次写入大量数据可能会在填满操作系统提供的缓冲区后停下来,只有在其他线程读取了一些初始数据后才会继续(当然,要小心死锁!),等等等等。
关于 (2)
,是的,日志模块是线程安全的,并且在某种程度上是“原子”的,也就是说,通过一次调用 logging.info、logging.warn、logging.error 等产生的数据在调用底层处理程序时是“完整的”(不过如果那个处理程序又使用了非原子的方式,比如 os.write,它可能仍然会在内核中停滞,直到底层缓冲区被清理等等,和上面说的一样)。