简体   繁体   English

如何从多线程应用程序打印到同一行

[英]How to print to the same line from multi-threaded application

I was using this code to notify the user of when REST interfaces had become available: 我正在使用以下代码来通知用户REST接口何时可用:

Console.printTermNoBreak("Waiting for interface on host [" + localTarget.getHostName() + "]");

When the interface came up then it would print 'OK' with a time stamp of how long it took to come up: 当界面出现时,它将打印“ OK”,并带有花费了多长时间的时间戳:

Console.SYS_LOGGER.info("[OK]" + " (" + (endTime - startTime + "ms") + ")");

On the console that would look as follows: 在控制台上,如下所示:

Waiting for interface on host [dubengvm272]         [OK] (413ms)

So both appenders write to the same line. 因此,两个追加程序都写入同一行。 I have refactored the code so that multiple threads bring up different interfaces on different machines. 我重构了代码,以便多个线程在不同的计算机上显示不同的接口。

Now because all the threads finish at different times the console is all garbled. 现在,因为所有线程在不同的时间结束,所以控制台都出现了乱码。 Just wondering if I can print out in the same way as before, even if it doesn't reflect exactly what is happening in the background. 只是想知道我是否可以以与以前相同的方式打印,即使它不能完全反映出背景中正在发生的事情。

If you want atomicity on a line-by-line basis you need to write out your line in one go. 如果您希望逐行原子化,则需要一次性写出您的行。 If your line consists of multiple parts you will need to first accumulate those parts into a single line and then write out that line when it's ready. 如果您的生产线由多个部分组成,则需要先将这些部分累加成一行,然后在准备好时将其写出。

But there are additional issues, even if individual threads write out complete lines at once you can still end up with lines overlapping each other. 但是,还有其他问题,即使单个线程一次写出完整的行,您仍然可能最终得到彼此重叠的行。 For example this can happen with buffered IO where the buffered writer is not thread-safe or when the line is large enough to exceed the buffer size and thus has to be broken down internally and written in multiple steps. 例如,在缓冲的IO发生这种情况的情况是:缓冲的写程序不是线程安全的,或者行的大小足以超出缓冲区的大小,因此必须在内部进行分解并分多个步骤进行写。

At least on linux writing to files/pipes opened with O_APPEND affords you some atomicity, but that's that's platform-specific, comes with some caveats and doesn't solve the buffering issue. 至少在Linux上,对使用O_APPEND打开的文件/管道进行写操作会给您一些原子性,但这是特定于平台的,带有一些警告,并且不能解决缓冲问题。

A more general solution for logging is to push your log items as a whole onto a thread-safe queue and have one thread poll from the queue and write to your output, item by item. 日志记录的一种更通用的解决方案是将日志项整体上推送到线程安全的队列中,并从队列中进行一次线程轮询,然后逐项写入输出中。 That way you can also have multi-line items. 这样,您还可以拥有多个订单项。

Having a separate logger thread also improves performance because logging is IO and can incur unnecessary latency on your main codepath. 拥有单独的记录器线程也可以提高性能,因为记录是IO,并且可能在主代码路径上引起不必要的延迟。 That way the logger thread becomes a "victim thread" for the IO penalty. 这样,记录器线程就成为IO罚款的“受害者线程”。

LinkedTransferQueue is a good candidate for the queue since submission to the queue does not block through a shared lock. LinkedTransferQueue是队列的理想选择,因为提交到队列不会通过共享锁阻止。 A potential downside that it is unbounded and can potentially cause OOMs in situations where the logger thread cannnot keep up with the log submitters. 在记录器线程无法跟上日志提交者的情况下,它存在无限的潜在弊端,并且可能导致OOM。 But if that happens you probably have some kind of problem anyway. 但是,如果发生这种情况,您可能仍然会遇到某种问题。

If your logger is already thread-safe then you simply have to write out your output in a single line instead of two separate log calls. 如果您的记录器已经是线程安全的,那么您只需要在一行中写出输出,而不是两个单独的日志调用即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM