从串行读取所需数据量的最佳实践? [英] Best Practise to Read Desired Amount of Data from Serial?

查看:38
本文介绍了从串行读取所需数据量的最佳实践?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于 read 仅会从序列中读取所有可用数据,因此此答案建议使用 while 循环等待,直到已读取所需的数据长度.但是AFAIK系统调用很昂贵,因此,这种方法难道不是很粗糙吗,尤其是在所需长度较大时?我知道这是否会导致性能问题取决于实际的应用程序,我不应该进行过早的优化.我很好奇,在这种情况下是否有更好的做法来避免密集的系统调用?

Since read would only read all available data from a serial, this answer suggests to use a while loop to wait until the desired length of data have been read. But AFAIK system calls are expensive, thus, isn't that approach somehow crude, especially when the desired length is large? I know whether this would cause a performance issue depends on the actual application, and I should not do premature optimization. I am just curious that whether there is a better practise to avoid intensive system calls in this scenario?

推荐答案

但是AFAIK系统调用非常昂贵,...

But AFAIK system calls are expensive, ...

是的,与本地过程/函数调用相比,系统调用可以消耗更多的CPU周期.系统调用需要在用户模式到(受保护的)内核模式之间进行CPU模式转换,然后再返回到用户模式.

True, a system call can consume many more CPU cycles than a local procedure/function call. The system call requires CPU-mode transitions between user-mode to (protected) kernel mode, and then back to user mode.

...因此,这种方法是否有点粗糙,尤其是在所需长度较大时?

... thus, isn't that approach somehow crude, especially when the desired length is large?

从串行终端(例如/dev/tty Xn设备)读取时,您必须问自己的第一个问题(而不是串行端口))是将要接收什么样的数据,即(ASCII)文本的数据以某种类型的EOL(行尾)字符终止,还是需要将数据简单地视为 binary (或原始)数据?"

The first question you have to ask yourself when reading from a serial terminal (e.g. a /dev/ttyXn device)(rather than a serial port) is "what kind of data is going to be received, that is, is the data lines of (ASCII) text terminated by some type of EOL (end of line) character, or does the data need to be simply treated as binary (or raw) data?"

应使用标准(又称熟化")模式从串行终端读取文本行.操作系统将对您的程序接收到的数据进行词法扫描,并根据您指定的EOL字符划定文本的每行 .然后 read()可以返回一行,假设使用了阻塞I/O,并且该文本行的长度不超过所提供的缓冲区的长度.

Lines of text should be read from a serial terminal using canonical (aka cooked) mode. The OS will perform a lexical scan of the received data for your program, and delimit each line of text based on the EOL characters you specify. The read() can then return a line assuming that blocking I/O is used, and the line of text is not longer than the buffer that is provided.

应使用非规范(aka原始)模式从串行终端读取二进制数据.操作系统将忽略数据值,并且(在使用阻塞I/O时)每个 read()都会根据时间和字节数的限制返回一定数量的数据.

Binary data should be read from a serial terminal using noncanonical (aka raw) mode. The OS will ignore the values of the data, and (when blocking I/O is used) each read() will return an amount of data based on constraints of time and number of bytes.

有关更多详细信息,请参见此答案.

See this answer for more details.

请注意,您的问题所涉及的帖子实际上是关于阅读文本的,但OP使用的是非规范模式.如果OP使用正确的模式来匹配输入,那么他可能永远不会出现部分读取问题.

Note that the post your question refers to actually is about reading text, yet the OP is (mis)using non-canonical mode. If the OP had used the proper mode to match the input, then he might have never had a partial-read problem.

我很好奇,在这种情况下是否有更好的做法来避免密集的系统调用?

I am just curious that whether there is a better practise to avoid intensive system calls in this scenario?

正确的termios配置对于使用串行终端进行有效的I/O至关重要.

Proper termios configuration is essential for efficient I/O with serial terminals.

应该将阻塞I/O模式视为首选模式.
当进程更频繁地放弃控制时,操作系统可以更好地执行多任务调度.
在确定何时可以将数据返回给用户时,操作系统更有效.
还要注意 termios 配置在使用阻塞模式时最有效,例如非规范模式下的VMIN和VTIME规范.

Blocking I/O mode should be considered the preferred mode.
The OS can perform its scheduling for multitasking better when processes relinquish control more often.
The OS is more efficient in determining when data is available for return to a user.
Note also that the termios configuration is most effective when blocking mode is used, e.g. the VMIN and VTIME specifications in noncanonical mode.

例如,使用 select() poll(),然后使用 read(),是比(阻塞) read().但是,您可以找到许多这样的代码示例,因为似乎存在一些普遍的误解,即程序可以从"UART"接口更快地获取数据.这样.
但是非阻塞和异步模式并不一定要更快(在多任务OS中), read()只是从termios缓冲区中获取数据,该缓冲区已从实际硬件中移走了几层.

For example using a select() or poll() and then a read() is one additional syscall more than when compared to just the (blocking) read(). And yet you can find many such code examples because there seems to be some popular misconception that the program can get the data faster from the "UART" that way.
But non-blocking and async modes are not necessarily faster (in a multitasking OS), and the read() merely fetches data from the termios buffer which is several layers removed from the actual hardware.

如果您的程序使用非阻塞模式,但是在等待数据时没有执行有用的工作,而是使用 select() poll()(甚至更糟)调用 sleep()),则您的程序不必要地复杂且效率低下.参见

If your program uses non-blocking mode but does not perform useful work while waiting for data, and instead uses select() or poll() (or even worse calls sleep()), then your program is unnecessarily complex and ineffecient. See this answer.
A blocking-mode read() can do all that waiting for your program, make your program simpler and easier to write and maintain, and be more runtime efficient.

但是,要阻止非规范读取,您将不得不接受某种程度的低效率.您可以做的最好的事情是权衡延迟与系统调用的数量.一个可能的示例是此答案,它试图获取尽可能多的信息每个系统调用中的数据,但可以轻松地对接收到的二进制数据进行逐字节的词法扫描.

However for blocking non-canonical reads, you will have to accept some degree of inefficiency. The best you can do is trade-off latency versus the number of syscalls. One possible example is this answer which tries to fetch as much data per syscall, yet allow for an easy byte-by-byte lexical scan of the received binary data.

请注意,读取串行终端时可能的延迟源是配置不良的内核,而不是termios API和 read()开销.
例如,通过 ioctl()设置ASYNC_LOW_LATENCY标志(例如,请参见

Note that a possible source of latency when reading a serial terminal is a poorly configured kernel, rather than the termios API and read() overhead.
For instance, setting the ASYNC_LOW_LATENCY flag via ioctl() (e.g. see High delay in RS232 communication on a PXA270) is one way to improve read() latency.

这篇关于从串行读取所需数据量的最佳实践?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆