【问题标题】:Python: is os.read() / os.write() on an os.pipe() threadsafe?Python:os.read() / os.write() 在 os.pipe() 线程上是安全的吗?
【发布时间】:2009-07-26 21:53:25
【问题描述】:

考虑:

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(), ... 编写的字符串必须保持为一体。

这些要求都满足了吗?

提前谢谢你,

简-菲利普·格尔克

【问题讨论】:

  • 顺便说一句:我知道Queue.Queue()select.select()。在我的特殊情况下,从线程 A 到线程 B 的通信将通过Queue.Queue():它传输“命令”。相比之下,B->A 会传输日志消息,应该如上所述通过os.pipe() 来实现,因为线程A 已经实现了基于select.select() 的事件循环,它可以监控pipe_read,如果出现则调用回调函数有一些可读的东西。

标签: python multithreading thread-safety pipe


【解决方案1】:

os.reados.writeos.pipe 返回的两个 fd 上是线程安全的,但您似乎要求的不止于此。子(1),是的,单次读取或写入没有“原子性”保证——您描述的场景(一次短写入最终产生两次读取)是完全可能的。 (通常, os.whatever 是操作系统功能的精简包装器,由操作系统来确保或无法确保您需要的功能类型;在这种情况下,Posix 标准不需要操作系统以确保这种“原子性”)。您可以保证以正确的顺序获取所有写入的数据,但仅此而已。大量数据的单次写入可能会在它填满操作系统提供的缓冲区后停止,并且只有在其他线程读取了一些初始数据后才会继续(当然要注意死锁!)等等。

Sub (2),是的,日志记录模块是线程安全的,并且在通过对 logging.info、logging.warn、logging.error 等的单次调用产生的数据中是“原子的”,在术语上“保持一体”对底层处理程序的调用(但是,如果该处理程序反过来使用非原子方式,例如 os.write,它可能仍然会在内核中停止,直到底层缓冲区被疏通等等,等等,如上所述)。

【讨论】:

  • 非常感谢您的回答。 “你保证得到所有写入的数据,并且以正确的顺序,但就是这样”->这就是我所需要的,因为这意味着我可以通过一个小的 post-os.read( ) 例行公事。现在我可以问心无愧地开始编码了。再次感谢您:-)
  • 不客气!您可以在每次“写入”开始时使用可区分的标记,以使重新组装后处理更容易。
  • 一些更新:实际上,我必须使用日志记录的StreamHandler() 而不是FileHandler()。来自 Python 文档:StreamHandler()“将日志输出发送到 [...] 任何类似文件的对象(或更准确地说,任何支持 write()flush() 方法的对象)。因此,我必须包装pipe_writeos.fdopen(),获取写入和刷新方法:logging.StreamHandler(os.fdopen(pipe_write,'a',0)) 我希望我选择了没有缓冲和附加模式的好选项。
  • 无缓冲绝对是尽可能接近裸露的 os.write;我相信“a”与“w”在这种情况下没有区别。
  • 它现在非常适合我。我写了一篇关于后处理步骤的需要和实现的博客文章:gehrcke.de/2009/08/… 我依赖于写入字符串的尾随换行符。这很方便,因为StreamHandler 会自动为每个日志字符串添加换行符!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 2015-04-18
  • 2011-10-07
  • 2012-03-02
  • 2011-10-28
  • 2023-03-14
  • 2016-08-24
相关资源
最近更新 更多