为什么Flask不能按正确的顺序显示控制台日志?

15 浏览
0 Comments

为什么Flask不能按正确的顺序显示控制台日志?

我了解到程序中的输入/输出默认是被缓冲的,也就是说它们是从临时存储中提供给请求的程序的。

我明白缓冲可以提高IO性能(可能是通过减少系统调用)。我见过禁用缓冲的例子,比如在C语言中使用的setvbuf函数。那么这两种模式之间有什么区别,以及在什么情况下应该使用其中一种?

0
0 Comments

Flask在显示控制台日志时为什么顺序不正确?

出现的原因:

1. 标准输出默认是缓冲的,因为假设会有大量的数据通过标准输出。相反,标准错误通常是非缓冲的,因为错误应该是很少发生的,希望能立即得到通知。

2. 如果日志消息在进程的缓冲区中,并且进程崩溃,有很大的可能性输出永远不会被写入。

3. 缓冲还可以减少系统调用和磁盘I/O的次数,在某些情况下提高性能。

解决方法:

1. 在需要确保输出已写入后再继续的情况下,使用非缓冲的输出。

2. 使用日志库时,及时将日志写入,避免进程崩溃时日志未被写入。

3. 在读取文件时,使用缓冲区可以提高性能,减少磁盘I/O的次数。

文章如下:

Flask在显示控制台日志时为什么顺序不正确?

出现的原因:

1. 标准输出默认是缓冲的,因为假设会有大量的数据通过标准输出。相反,标准错误通常是非缓冲的,因为错误应该是很少发生的,希望能立即得到通知。

2. 如果日志消息在进程的缓冲区中,并且进程崩溃,有很大的可能性输出永远不会被写入。

3. 缓冲还可以减少系统调用和磁盘I/O的次数,在某些情况下提高性能。

解决方法:

1. 在需要确保输出已写入后再继续的情况下,使用非缓冲的输出。

2. 使用日志库时,及时将日志写入,避免进程崩溃时日志未被写入。

3. 在读取文件时,使用缓冲区可以提高性能,减少磁盘I/O的次数。

这里有一个例子,展示了缓冲可以采取的不同形式。一个进程A使用C运行时库,另一个进程B也使用C运行时库,并具有C运行时库的缓冲。

+-------------------+-------------------+
| Process A         | Process B         |
+-------------------+-------------------+
| C runtime library | C runtime library | C RTL buffers
+-------------------+-------------------+
|               OS caches               | Operating system buffers
+---------------------------------------+
|      Disk controller hardware cache   | Disk hardware buffers
+---------------------------------------+
|                   Disk                |
+---------------------------------------+

值得一提的是,一个FILE对象(流)的内部缓冲区与fgets所需的缓冲区参数完全不同。这让我在写了一些代码来解决问题之前困惑了几个小时。QAQ

难道没有人会一次读取一个字节的方式读取文件吗?

- 当然有。一个标准的I/O过滤程序通常使用getchar/putchar,并依赖于缓冲区提供效率,至少在I/O设备上的读写操作上。

但是,如果我打开一个文件,执行单个大的读/写操作,然后关闭,如果不使用缓冲区,会变慢吗?

- 可能会变慢,但通常不知道数据源(或目标)的属性。是来自标准输入还是文件,是来自本地文件还是网络挂载的文件,是以300比特每秒运行的终端设备,还是连接到可能不时传递数据的另一个进程的管道?UNIX文件模型的强大之处("一切皆文件")也使得很难确定性地定制I/O策略。

一个在磁盘上的文件,比如应用程序的配置文件?

- 配置文件可能很小,足够一次性读入内存并从内存中使用(并且很可能在本地磁盘上,但并不保证)。对于这种情况,我可能会尝试以10K的块来读取,因为通常只需要一次读取操作,且10K不会造成太多的浪费,即使配置文件只有二十个字节的长度:-)

当你提到"OS caches"时,你实际上是指硬件CPU缓存(如L1、L2、L3等)还是"OS caches"是内核空间内的某种缓冲区?

- 我指的是操作系统级别的缓存。CPU缓存更低级别,与内存访问而非文件I/O有关。

0
0 Comments

为什么Flask在控制台中不按正确顺序显示日志?

问题的原因是Flask默认使用缓冲输出流来提高写入性能。缓冲输出流会将写入结果暂存在一个中间缓冲区中,只有当积累了足够的数据时(或者调用了flush()方法),才会将数据发送到操作系统的文件系统中。这样可以减少文件系统调用的次数,从而提高性能。然而,缓冲输出流会导致日志输出的顺序混乱,因为数据并不是即时写入文件系统。

解决方法是使用无缓冲输出流来确保日志按正确的顺序显示。在Flask中,可以通过设置app.logger的stream属性来实现。具体做法是创建一个无缓冲的输出流对象(如sys.stdout.buffer),然后将其赋值给app.logger的stream属性。这样就可以确保日志会即时写入文件系统,而不会出现顺序混乱的问题。

另外,需要注意的是,无缓冲输出并不能保证数据已经写入物理磁盘。操作系统文件系统有权暂时保存数据,并在需要时再写入磁盘。要确保数据已经写入磁盘,可以使用O_SYNC标记(在WinAPI中的CreateFile函数中使用FILE_FLAG_NO_BUFFERING和FILE_FLAG_WRITE_THROUGH标记)。不同的操作系统可能有不同的方式来实现无缓冲输出和数据持久化的功能。

总结起来,为了解决Flask控制台日志显示顺序混乱的问题,可以通过使用无缓冲输出流并设置O_SYNC标记来确保日志按正确的顺序显示并持久化到磁盘。

0