使用多个线程时不同步的打印消息

Posted

技术标签:

【中文标题】使用多个线程时不同步的打印消息【英文标题】:Unsynchronized printed messages when working with multiple threads 【发布时间】:2022-01-19 01:43:40 【问题描述】:

我正在编写某种具有非常简单界面的终端聊天应用程序:

[Me] Here I write my messages.
[Me] When the Enter key is pressed, the message is sent to other users.
[user1] Other users can also send me messages.
[user2] Their usernames are shown at the start of the line, between square brackets.

这个应用程序的主线程只是等到用户写完一条消息并按下回车键:

msg = input('[Me] ')
# Do stuff with msg...

从其他用户收到的消息通过一个简单的print 函数调用(在其他线程中运行)显示在屏幕上:

print(f'\n[msg_author] msg_content')

问题是我无法以漂亮的方式处理从其他用户收到的消息的打印。比如收到一条新消息后,屏幕的状态可能是下一个:

[Me]
[user1] New message appeared!

由于print函数因为新消息而运行,现在应用程序仍在等待我写消息,但光标在新行(注意最后一个空行),所以如果我开始写一条消息,它会这样显示

[Me]
[user1] New message appeared!
I'm writing here...

当屏幕更新到更漂亮的方式时

[user1] New message appeared!
[Me] This will be the way!

当我写了我的新消息的某些部分(没有按 Enter)并收到新消息时,这是一个更大的问题:

[Me] I have still not finished this message...
[user1] Another message appeared!

我写的信息应该是这样显示的:

[user1] Another message appeared!
[Me] I have still not finished this message... And I would like to continue it down here!!!

我知道CSI sequences的存在,但我相信他们无助于解决这个问题(实际上,我什至不知道这是否可以使用input函数来询问消息)。

【问题讨论】:

【参考方案1】:

您似乎正在编写“控制台应用程序”。您需要知道的第一件事是控制台不是您的应用程序的一部分。它是一个完全独立的东西,通过“管道”与您的应用程序通信。控制台是对 20 世纪 computer terminal 的模拟,最初的计算机终端并不是为可以与等待输入异步生成输出的应用程序而设计的。

IMO 你有两个选择。更好的方法是构建一个完整的 GUI 应用程序而不是控制台应用程序。为此,您需要使用 GUI 框架,例如 PyQt5、WxPython 等。不幸的是,如果您还没有进行任何 GUI 编程,那么在您之前还有很多东西需要学习能够创建一个类似于聊天的 GUI,它与智能手机上的消息传递应用程序一样流畅。

另一种选择是构建一个控制台应用程序,该应用程序使用ANSI escape sequences 创建有点类似于 GUI 的用户体验。我强烈建议您使用 3rd 方库,例如 ncurses 来帮助解决这个问题。仍然会有一些学习曲线,但可能不会那么陡峭。

IMO:第一次使用 ncurses,我会将控制台屏幕分成两个窗口;底部有一个小的,本地用户可以编辑他们的下一条消息,而一个较大的则填满屏幕的其余部分,本地用户可以看到他们之前的消息与来自远程用户的消息交错排列。

我自己在 ncurses 方面做得还不够,无法向您展示任何示例代码。但也许您可以在 Internet 上找到示例。

【讨论】:

【参考方案2】:

仅使用inputprint,您将很难或不可能做到这一点。建议您查看以下任何一项:

https://github.com/erikrose/blessings https://urwid.org/

【讨论】:

以上是关于使用多个线程时不同步的打印消息的主要内容,如果未能解决你的问题,请参考以下文章

线程同步与相互排斥:相互排斥锁

线程安全与线程不安全

什么是线程同步,什么是线程异步?同步的好处与弊端

多线程中同步和异步?

多线程的同步和互斥有啥区别

java多线程 更优雅的实现线程同步:交替打印AB LockSupport实现