LabVIEW_基于Network Steams 的无损传输技术

LabVIEW提供了用于创建分布式应用程序的多种技术的访问权限。LabVIEW 2010中引入的网络流是在这些应用程序之间流传输数据的理想方法。使用网络流,您可以轻松地在网络上或同一台计算机上共享数据。本文是对网络流进行介绍,并讨论了其功能和性能。

简介:

网络流是一种易于配置,紧密集成的动态通信方法,用于将数据从一个应用程序传输到另一个应用程序,其吞吐量和延迟特性与TCP相当。但是,与TCP不同,网络流直接支持任意数据类型的传输,而无需先将数据平化和平化为中间数据类型。网络流以向后兼容的方式使数据扁平化,这使使用不同版本LabVIEW运行时引擎的应用程序能够安全,成功地相互通信。网络流还具有增强的连接管理,如果由于网络中断或其他系统故障而导致断开连接,则可以自动恢复网络连接。流使用一种缓冲的,无损的通信策略,即使在具有间歇性网络连接的环境中,也可以确保写入流中的数据不会丢失。

具体用途

网络流是为无损,高吞吐量数据通信而设计和优化的。网络流使用单向,点对点缓冲的通信模型在应用程序之间传输数据。这意味着端点之一是数据的写入者,另一个是读取器。您可以使用两个流来完成双向通信,其中每台计算机都包含一个读取器和一个写入器,并与另一台计算机上的写入器和读取器配对。

由于构建的流具有与原始TCP相当的吞吐量特性,因此对于程序员不想处理使用TCP的复杂性的高吞吐量应用程序,流是理想的选择。流还可以用于无损,低吞吐量的通信,例如发送和接收命令。但是,如果需要绝对最低的延迟,则将流用于低吞吐量通信可能需要对何时通过流传输数据进行更明确的管理。

图片

基本编程模型
完成以下步骤以使用网络流创建和流传输数据:
1.创建端点并建立流连接。
2.读取或写入数据。
3.销毁端点。
下图显示了这些步骤的实现。

图片

接下来将详细介绍使用Network进行数据通信性能及注意事项.

端点网址
LabVIEW使用URL识别每个流端点。要连接两个端点并创建有效的网络流,必须使用“创建网络流端点读取器”或“创建网络流端点写入器”功能指定远程端点的URL。有关端点URL的更多详细信息,包括保留字符的转义码,可在LabVIEW帮助中的“指定网络流端点URL”主题下找到。但是,为了完整起见,这里还将提供URL的简短描述。

ni.dex://host_name:context_name/endpoint_name

以下列表描述了此URL的不同组成部分:

ni.dex是URL的协议,是可选的。如未在创建函数中指定ni.dex,LabVIEW将推断该协议。host_name是终结点计算机所在的项目的别名,DNS名称或IP地址。此外,字符串“ localhost”可以用作当前在其上执行代码的计算机的假名。如果将host_name留为空白,则将推断localhost。LabVIEW按以下顺序搜索匹配的主机名:项目别名,DNS名称,然后是IP地址。

context_name是标识终结点驻留在哪个应用程序上下文中的名称。仅当同一计算机上的多个应用程序实例正在使用网络流功能时,才需要此名称。(如果是比跑代码,这个名称就是LabVIEW,打包的程序就是程序名称、如果webService就是webService的名称)默认情况下,上下文名称为空字符串,并且所有端点均在默认上下文中创建。使用默认上下文时,可以省略冒号分隔符。endpoint_name是流终结点的实际名称。此名称可以是平面字符串或由正斜杠字符分隔的字符串的分层路径。例如,流1或子系统A /流1。您必须使用创建端点功能指定的URL会有所不同,具体取决于远程计算机的网络位置以及在创建端点时分配给端点的名称。

创建端点并建立流

网络流是写入器和读取器端点之间的连接。您可以使用“创建网络流编写器端点”或“创建网络流读取器端点”功能来创建端点。

图片

与TCP不同,网络流直接支持LabVIEW数据的传输,而不必在字符串之间展平和展平数据。网络流直接支持大多数LabVIEW数据类型。但是,一些值得注意的例外包括包含对象引用或LabVIEW类作为其类型一部分的数据类型。通过首先在类上创建转换方法以序列化和反序列化适当的类数据,仍可以间接传输类。由于引用是引用本地计算机上对象引用,因此通常无法尝试通过网络发送引用以供远程计算机使用。一个例外是视觉图像数据类型,如果安装了NI视觉开发模块,则可以使用。在这种情况下,通过使用对视觉图像数据的引用,流直接支持图像数据的传输。流不直接支持的任何数据类型都将需要转换代码,以将数据与一种支持的类型进行相互转换。另外,某些数据类型比其他数据类型更有效地通过流传输。有关所选数据类型如何影响流性能的更多信息,请参见性能注意事项部分。

除了创建端点资源之外,create函数还将链接书写者和阅读者端点在一起,以形成功能完善的流。首先创建的端点将等待,直到另一个端点已创建并准备好进行连接,这时两个创建功能都将退出。然后,该流已准备好传输数据。以这种方式使用时,create函数有效地充当了一个网络集合点,其中在流的两边都准备就绪或create调用超时之前,create函数都不会进行。

为了在两个端点之间建立流,必须满足三个条件。

1.两个端点都必须存在。此外,如果两个创建函数都指定了要链接的远程端点URL,则两个URL必须与要链接的端点匹配。

2.两个端点的数据类型必须匹配。

3.端点之一必须是只写端点,另一个端点必须是只读端点。

如果执行创建函数时最初不满足条件一个,它将等待直到超时到期,如果仍然不满足条件,则返回超时错误。如果两个端点都指定了要链接的另一个端点,并且只有一个URL匹配,则一个create函数将返回错误,而另一个将继续等待直到超时到期。

图片

例如,在上面的示例中,左侧的create调用将返回错误,因为“ reader1”端点期望与名为“some other writer”而不是“ writer1”的端点进行通信。但是,右侧的create调用将继续等待,直到名为“some other writer”的终结点的超时终止,然后再返回超时错误。如果不满足两个或三个条件,则一旦确定两个端点的配置与形成流不兼容,create函数将返回错误。

创建端点时,请记住,至少一个创建端点函数需要在读取器URL或写入器URL输入中指定另一个端点的URL。否则,将确保两个create调用最终都将返回超时错误。读取者和写入者端点都可以在其create函数中指定彼此的URL,但仅需一个。为了开发更可移植和可维护的代码,National Instruments建议仅读取者或写入者指定另一个端点的URL,但不要同时指定两者。

端点缓冲区

流端点使用FIFO缓冲区将数据从一个端点传输到另一端点。缓冲区大小是在创建时指定的,并且缓冲区是在create调用中分配的。缓冲区的大小以元素为单位指定,其中缓冲区中的元素表示由流的数据类型指定的类型的单个值。因此,端点消耗的内存总量将根据缓冲区大小和流的数据类型而变化。

对于标量数据类型(如布尔值和数字),端点缓冲区消耗的内存量很容易计算,因为标量数据类型的大小是一个固定量,可以提前知道。例如,双精度浮点数的1,000个元素的缓冲区将消耗8,000个字节的内存,因为双精度浮点数始终会消耗8个字节的内存。

另一方面,处理非标量数据类型(例如群集,字符串和数组)时消耗的内存量并不是那么简单。这些数据类型的大小在运行时可能会有所不同,因此创建端点时不知道所需的内存总量。在这些情况下,创建端点时分配的缓冲区仅足够大,以使每个元素都可以保留指向写入缓冲区中该元素的数据值的指针或句柄。然后,在将元素写入缓冲区时,会在运行时动态分配存储每个元素的数据值所需的内存。下图有助于说明缓冲区大小为3且元素数据类型为1D数组的流终结点的这一概念。

图片

步骤A显示刚创建后的端点缓冲区。此时,尚未向端点写入任何数据值,并且已为每个元素分配足够的内存来存储指针,该指针将指向包含该元素数据值的存储块。

步骤B显示了将三个数据值写入缓冲区后的端点缓冲区。元素1包含一个长度为2的数组。元素2包含长度为4的数组。最后,元素3包含长度为3的数组。因为这是第一次写入缓冲区,所以每次写入都会动态分配一个内存块,该内存块足以容纳每个数据值。

在从缓冲区读取了所有三个数据值之后,步骤C显示了端点缓冲区。请注意,即使已从缓冲区中读取了所有值,也不会放弃为每个数据值分配的内存。而是保留了存储空间,因此可以将其重新用于在缓冲区中的该位置存储下一个数据值。

步骤D显示了在写入了另外两个长度为3的数据值之后的端点缓冲区。在这种情况下,元素1维护的存储块的大小不足以容纳新的数据值,因此必须分配更大的存储块。相反,由元素2维护的存储块足够大以容纳新的数据值并被重用。请注意,即使元素2维护的内存块大于所需的内存块,它仍然可以重用,而不会产生取消分配内存并分配具有所需大小的新块的执行开销。一旦为一个元素分配了一个内存块,它就不会被释放或减小大小,直到端点被销毁为止。

如该过程所示,您必须为非标量数据类型仔细选择端点缓冲区大小。如果数据元素很大且缓冲区大小很大,则端点可能会消耗大量内存,直到端点被销毁为止。对于标量数据类型也是如此。但是,调试标量数据类型的内存问题通常要容易得多,因为在创建端点时会立即分配所有必需的内存。相反,非标量类型所需的大多数内存是在第一次填充缓冲区时分配的。由于端点缓冲区已满,应用程序可能会先运行一段时间,然后再用尽内存,这通常会显示为内存泄漏。

读写数据

流上的所有读写调用都将阻止本质上是事务性的调用。他们要么成功读取或写入请求数量的元素,要么超时。在超时的情况下,不会读取或写入部分数据,并且永远不会覆盖或重新生成数据。如果读取调用导致超时,则数据输出终端将返回已配置数据类型的默认值。这意味着在一次调用中可以读取或写入的最大元素数受端点缓冲区大小的限制。读取或写入多个大于端点缓冲区大小的元素的请求将立即导致错误。

图片

在读取和写入数据时,网络流同时提供单元素和多元素接口。单元素读写允许一次添加一个元素或从缓冲区中删除一个元素,而多元素读写允许批量添加或删除数据。当使用不同类型的读写时,程序框图上数据的表示形式将有所不同。在下面的示例中,流的数据类型是双精度浮点数。使用单元素写入对流进行写入在框图上用double数据类型表示。另一方面,终端中用于多元素写入数据的数据类型由双精度数组表示。

图片

下图进一步说明了这种差异。箭头左侧的元素表示写操作发生之前的写程序端点缓冲区,箭头右侧的元素表示执行写操作后的写程序端点缓冲区。如果writer端点缓冲区最初包含两个元素,则执行单个元素写入将向缓冲区添加一个元素,并使缓冲区中的元素总数达到三个。如果改用写多个元素到流功能来写三个元素,则缓冲区中的元素总数为五个。

图片

对于非标量数据类型,例如数组,上面的图看起来相同,但是各个元素的内容是数组类型,其长度可以变化。在这种情况下,用于单元素写入的数据类型是一维数组,而用于多元素写入的数据类型是2D数组。下图说明了这一点,其中向上箭头和其上方的框代表阵列及其各自的大小。

图片

同样,读取多个元素将删除从读取器端点缓冲区中指定数量的元素。但是,由于LabVIEW中多维数组结构的限制,所有数组元素必须具有相同的尺寸长度。对于多个元素读取,这意味着如果尝试读取多个数组元素中任意一个数组元素的尺寸长度不同的元素,则将从读取函数返回错误。以图4为例,这意味着您可以成功读取单个读取调用中的第一个元素,单个读取调用中的第二个元素以及单个读取调用中的第三到第五个元素。但是,由于数组元素的尺寸长度不同,任何尝试读取第一到第三元素的任何组合的读取调用都将返回错误。由于单个元素和多个元素的读写是从同一缓冲区中删除和添加元素,因此多速率应用程序可以根据需要混合和匹配单个元素和多个元素的读写。

当使用多元素读取功能时,#元素输入的值-1表示读取所有可用样本。

图片

这等效于读取“可供读取的元素”属性,并将返回值用作输入到读取函数的#个元素的输入,并且是完成相同操作的简便方法。以这种方式使用时,有效地禁用了以毫秒为单位的输入到读取功能的超时。如果没有可供读取的元素,则读取函数将立即返回一个空数据数组,而不指示超时或错误情况。

关闭流

当不再需要在端点之间流式传输数据时,可以通过调用销毁流端点功能来停止从任一端点进行通信。

图片

但是,如果要确保在销毁写入器端点之前读取器已接收到所有写入流的数据,则必须首先调用Flush Stream函数并等待适当的等待条件得到满足,然后销毁写入器端点。只有编写者端点可以调用flush函数。

图片

刷新功能首先要求仍然驻留在写入器端点缓冲区中的所有数据立即通过网络传输。然后,它等待直到满足指定的等待条件或超时到期。刷新流功能具有两种不同的等待条件:

从流中读取所有元素

所有可供阅读的元素

当您指定“从流读取所有元素”时,刷新功能将等待,直到所有数据都已传输到读取器端点,并且所有数据已从读取器端点读取后再返回。“所有可读取的元素”选项将等待,直到所有数据都已传输到读取器端点,但不会等到从读取器端点读取了所有数据。使用下图作为指导,“所有可读取的元素”选项将在步骤C之后从刷新调用返回,而“所有从流读取的元素”选项将在步骤D之后返回。

图片

在销毁写入器端点之前未能调用刷新意味着传输中的任何数据或仍驻留在写入器端点缓冲区中的任何数据都可能丢失。因此,National Instruments建议您在关闭流之前先调用flush,除非您的应用程序需要立即停止通信并且您不需要在此过程中可能丢失的任何数据。

一旦在读取器端点上调用了destroy,则随后从写入器端点进行的任何写调用都将导致错误。当写入器端点已被销毁时,来自读取器端点的后续读取调用将继续成功,直到读取器端点缓冲区为空为止,此时读取调用将返回错误。如果收到的多元素读取请求中的元素超出了缓冲区中剩余的元素,则读取请求将返回缓冲区中剩余的所有元素,随后的读取请求将引发错误。

属性

网络流具有许多可用属性,应用程序可以监视这些属性以获得有关正在进行的数据流的信息。其中一些属性将在下面更详细地说明。有关其余属性的信息,请参见LabVIEW帮助中的“网络流端点属性”页面。

图片

阅读器端点使用“可供读取的元素”来返回驻留在端点缓冲区中的未读元素的数量。这对于确定读取器端点缓冲区的使用很有用,并且仅在从读取器端点读取时才返回有效结果。同样,“可写入的可用元素”属性返回驻留在端点缓冲区中且只能由写入器端点读取的未写入元素的数量。在对应用程序进行原型设计时,监视缓冲区利用率通常很有用,以便了解读取器和写入器之间的相互配合程度。此信息可用于确定应用程序中的瓶颈,并微调端点缓冲区的大小,以便消耗最少的内存资源,同时仍然满足应用程序的总体吞吐量要求。

Connected属性指示读取器和写入器端点之间的网络连接状态。连接属性上的false表示使用Destroy Stream Endpoint函数破坏了另一个端点,或者两个端点之间的网络连接中断。在网络中断的情况下,端点将不断尝试在后台重新连接,直到解决了中断或端点被销毁为止。

断开连接数返回读取器和写入器端点之间的网络连接由于网络问题或远程端点被破坏而中断的次数。该属性与Connected属性一起可用于确定连接读取器和写入器端点的网络的一般稳定性和运行状况。

无损数据传输和流量控制

如前所述,网络流提供点对点通信通道,该通道保留所有写入的数据,直到已从流中读取数据或销毁该流为止。通过使用端点缓冲区上的FIFO缓冲区策略以及确认和流控制协议消息,可以实现这种无损数据传输。FIFO缓冲区策略可防止包含编写者终结点的应用程序试图以比网络可以传输的速度快的速度写入数据。确认消息可防止由于网络断开而造成数据丢失,而流控制消息则可防止包含写入器端点的应用程序试图覆盖包含读取器端点的应用程序消耗数据的速度而覆盖数据。以下序列图更详细地说明了如何使用这些消息来确保无损数据通信。

图片

1.时隙1显示了三个端点缓冲区都为空的三个元素的写请求。

2.由于writer端点可以接受三个元素而不会覆盖数据,因此写请求完成,并且writer端点现在包含三个元素。

3.编写器端点将三个元素发送到读取器端点。此时,写入器端点内的三个元素以红色阴影显示,以指示在读取器端点进行确认之前,这些元素仍处于占用状态。在收到确认之前,编写者必须保留这三个元素,并且最多可以发送两个其他元素。

4.读取器端点从写入器接收三个元素。在写程序端点上发出两个元素的写请求。

5.阅读器端点发送三个元素的确认。由于写入者端点可以接受两个元素而不会覆盖数据,因此来自时隙4的先前写入请求完成,并且写入者现在包含五个元素。

6.编写者端点收到三个元素的确认。它从其端点缓冲区中删除了三个元素,现在它包含两个元素。

7. Writer端点将两个元素发送到Reader端点。但是,在传输过程中,存在网络中断,读取器永远不会接收到数据。

8.收到四个元素的写请求。由于写者端点只能接受三个元素而不能覆盖数据,因此写调用将阻塞。

9.流已修复网络连接,并检测到发送了两个从未收到的元素。这些元素在重新连接过程中重新发送。

10.阅读器端点接收到两个重发元素。读者现在包含五个要素并且已满。在从读取器端点读取数据之前,写入器无法发送更多元素。

11.阅读器端点发送两个元素的确认。同时,接收到两个元素的读取请求。

12.编写者端点收到两个元素的确认,并将其从其端点缓冲区中删除。编写器现在为空。由于阅读器具有五个元素,因此它完成了先前对两个元素的读取请求,并将两个元素的流控制消息发送到编写者端点,以使其知道可以接受另外两个元素而不会产生溢出。读者现在包含三个要素。

13.由于写入器现在具有五个空闲元素,因此它将完成已阻塞的时隙8中的写入请求。作者现在包含四个元素。另外,它从阅读器接收两个元素的流控制消息。现在,它最多可以将两个其他元素发送到读取器,直到接收到其他流控制消息为止。

连接管理和重新连接

在上一节中,我们展示了即使在基础网络存在连接问题的情况下,网络流也如何保持无损数据传输。本节将详细讨论如何管理此重新连接过程。

在任何给定的网络流中,一个端点被指定为主动端点,另一个端点被指定为被动端点。活动端点是始发初始网络连接的端点,它负责在检测到网络状态断开连接时主动尝试重新建立连接。相反,被动端点是侦听或等待接收连接请求的端点。在客户端/服务器术语方面,主动端点与客户端同义,被动端点与服务器同义。创建端点函数指定哪个端点是活动端点。将指定要连接的远程端点的URL的端点指定为主动端点,将未指定远程端点URL的端点指定为被动端点。

图片

在上图中,左侧的writer端点是活动端点,因为它指定了所连接的Reader端点的URL。另一方面,右侧的阅读器端点未指定要连接的端点的URL,因此被指定为被动端点。如果两个端点都指定了它们要连接的远程端点,则被指定为活动端点的端点不确定,并且将取决于在网络上发送和接收协议消息的顺序。

在断开连接的情况下,主动端点将连续尝试在后台与被动端点重新建立通信。该后台过程将继续进行,直到修复连接或终结点为止。在断开连接状态下,写入器端点的写入将继续成功,直到写入器已满,并且从读取器端点进行的读取将继续成功,直到读取器为空。一旦写入器已满或读取器为空,则读写调用将阻塞并返回相应的超时指示符。但是,读或写调用本身不会返回任何错误。

尽管端点缓冲区可提供某种程度的保护,以防止由于网络不可靠而引起的抖动,但如果网络断开连接的时间过长,它们最终将填满或变空。如果您的应用程序需要忍受长时间的网络中断,则应该调整端点缓冲区的大小以吸收最大的预期停机时间,或者实施适当的逻辑以在断开状态下处理超时情况。另外,尽管流能够识别出处于断开状态,但它始终无法区分断开是由于网络问题,应用程序崩溃还是从包含远程端点的应用程序挂起而导致的。在崩溃或挂起的情况下,如果崩溃的端点是主动端点,则仍在运行的被动端点将永远等待以接收重新连接。由于远程应用程序不再响应,因此该消息将永远不会到达,并且本地应用程序在流连接方面将不会取得任何进一步的进展。如果您的应用需要容忍并从远程应用崩溃或挂起中恢复过来,建议您通过定期检查Connected属性并在无法在合理的时间内重新建立通信的情况下采取适当的措施来实现自己的看门狗计时器。

性能考量

调整网络流性能时的两个常见指标是吞吐量和延迟。测得的吞吐量和等待时间取决于许多因素,包括通信中涉及的系统的规格,用于通信的网络接口以及网络本身的总体拥塞和可靠性。尽管很重要,但是对这些因素的详细讨论超出了本文的范围。取而代之的是,本文将重点介绍可在应用程序中以编程方式配置的网络流特有的属性。

最大化吞吐量

下面显示并描述了最通常限制网络流吞吐量的组件。

图片

1.编写器应用程序–这是包含编写器端点的用户应用程序。这通常会涉及一个调用Write Function的循环。

2.写入功能–写入功能代表从写入者应用程序接收数据并将其传输到写入者端点的成本。

3. Network StreamsEngine –这是后台进程,该进程将数据从写入器端点异步移动到读取器端点,并从读取器端点向写入器端点发送确认和流控制消息。

4.读取功能–读取功能表示从读取器端点删除数据并将其传输到读取器应用程序的成本。

5.阅读器应用程序–这是包含阅读器端点的用户应用程序。这通常会涉及一个调用读取功能的循环。

请注意,Writer应用程序,网络流引擎和Reader应用程序都是异步进程,它们彼此并行运行,并且总流吞吐量将由最慢的进程决定。在此,将执行写入功能的时间包括在写入器应用程序中,将执行读取功能的时间包括在读取器应用程序中。许多流属性将影响这些过程,下面将对其进行详细讨论。

端点缓冲区大小

流端点的默认缓冲区大小为4096个元素。该值往往是在实现标量数据类型的良好吞吐量而又不为非标量数据类型消耗大量内存的情况下的一个很好的折衷,在非标量数据类型中,每个非标量元素的大小可能非常大。尽管对于标量和非标量类型,这往往是吞吐量和内存利用率之间的良好折衷,但通常不会为这两种情况提供最佳设置。对于标量数据类型,端点缓冲区大小可能需要在100,000或1,000,000个元素的数量级上才能实现给定网络接口的最大吞吐量。对于非标量类型,通常可以使用小得多的缓冲区来实现最大吞吐量。

幸的是,没有确定最佳缓冲区大小的简单公式。在开发过程中,您通常不得不尝试不同的缓冲区大小,以确定哪种设置最适合您的应用程序需求。作为原型的一部分,您可以使用“用于读取的可用元素”和“用于写入的可用元素”属性来确定每个端点缓冲区的利用效率以及当前缓冲区的大小是否成为应用程序的瓶颈。

例如,如果您没有达到所需的吞吐量,并且写入器端点始终处于满或接近满状态,则表明Network Streams Engine与写入器应用程序不同步。此行为通常表示网络已饱和并且已达到其吞吐量限制,或者写入程序端点缓冲区太小。在后一种情况下,网络流引擎从写入器端点发送元素并从读取器端点接收确认和流控制消息的网络延迟限制了写入器应用程序的循环速率。在这种情况下,您可以通过增加写入程序端点缓冲区的大小来提高吞吐量。

同样,如果您没有达到所需的吞吐量,并且阅读器端点缓冲区始终为空或几乎为空,则表明Network Streams Engine跟不上阅读器应用程序。此行为再次表明网络已达到饱和或读取器端点缓冲区太小。假设网络尚未达到饱和,那么增加读取器端点缓冲区的大小通常会提高吞吐量。

读写元素数

读写数据时要记住的重要一点是,无论每次读写调用实际传输了多少数据,调用读写函数的成本都是固定的。如果您经常使用相对较小的数据集调用读写,那么花费在函数固定开销上的总执行时间将变得越来越重要。如果此开销变得足够大,则运行Writer Application或Reader Application的处理器可能会在100%的利用率下达到饱和。发生这种情况时,处理器将无法再足够快地执行应用程序循环以跟上NetworkStreams Engine的速度,从而使应用程序成为瓶颈。

为了帮助诊断此问题,您可以结合使用运行该应用程序的处理器来查看端点缓冲区的利用率。如果处理器利用率接近100%,而写入器端点为空或几乎始终为空,则表明写入器应用程序无法与NetworkStreams Engine保持同步。同样,如果处理器利用率接近100%,并且读取器端点缓冲区已满或几乎总是满,则表明读取器应用程序无法跟上Network Streams Engine的速度。在这些情况下,增加单个调用中读取或写入的元素数量可以提高整体吞吐量。另外,对于可变大小的数据类型,您可以尝试增加写入流的每个元素的大小。例如,如果您的元素类型是一维数组,则可以尝试编写单个10,000个元素数组,而不是一千个10个元素数组。

就像一次读写太少的数据可能会损害吞吐量一样,一次读写太多的数据也是如此。对于大型数据集,分页数据进出系统内存所产生的开销最终将超过不那么频繁地调用读取或写入函数所节省的开销。在开始成为限制因素之前,数据集的大小取决于系统,并且将取决于系统包含的物理内存量而变化。为避免这些问题,许多应用程序的一个好的经验法则是,每次读取或写入调用时,读取或写入总缓冲区大小的1/10至1/4。

元素数据类型

流的数据类型也将直接影响在通过网络发送和接收数据时,为了使数据平坦和不平坦,读取和写入功能需要执行多少工作。因此,较复杂的数据类型将比较简单的数据类型具有较差的吞吐量。传输给定数据类型的元素所需的工作量取决于以下因素:

1.数据类型本身的复杂性和大小。例如,像簇这样的任意数据类型(包括其他数据类型作为子元素,并且可以包含任意级别的嵌套)在本质上比具有固定结构的数据类型解析和构造更为复杂。

2.流端点可以有效地管理存储数据类型的元素所需的内存。如果数据类型的大小固定,则端点可以将所有元素存储在连续的内存块中。如果数据类型为可变大小,则端点必须管理多个内存块,并偶尔在运行时分配和取消分配内存。

根据这些标准,标量数据类型既简单又固定大小,因此效率最高,并且吞吐量最佳。大小不同但仍归类为简单的数据类型将具有次佳的吞吐量。此类数据类型包括标量和字符串数组。最后,大小不同且具有复杂数据层次结构的数据类型(例如群集和群集阵列)将表现出最差的性能。为了获得最高的吞吐量,您应尽可能使用标量数据类型。

最小化延迟

默认情况下,网络流被设计为在保持合理延迟的同时尽可能有效地利用网络带宽。这意味着,当将数据写入流时,在通过网络传输数据流之前,数据流可能会保留一段时间。这样做是为了将连续多次写入的数据捆绑在一起,并作为单个大TCP数据包通过网络(而不是一系列较小的数据包)发送。流使用启发式方法来确定在传输数据之前要等待多长时间,而与待处理的数据量无关,这取决于实现方式,并且可能因版本而异。尽管这有助于最大程度地减少由于TCP数据包开销而浪费的带宽,但同时也增加了低吞吐量数据流的默认延迟。如果将流用于两个应用程序之间的命令通信,则此额外的等待时间可能是不希望的。为了缓解此问题,可以在写入函数之后立即调用flush函数,如下图所示。

图片

向刷新函数传递零超时将迫使写入器端点立即将所有数据发送到读取器端点,而无需等待数据被读取器端点接收或读取。这种编程技术将在不阻止编写器应用程序执行的情况下,为发送数据提供最低的延迟。

网络流的局限性

尽管网络流为通过网络进行点对点通信提供了更高的易用性,但是在某些情况下,网络流可能不适合您的应用程序。 

通常,网络流不适合在控制算法中使用。以太网通常不是用于控制应用程序的可靠通信总线,并且对流的读写不确定。网络流仍可以在控制应用程序中用于与远程HMI进行通信,但是在任何时间紧迫的循环中都不应使用网络流。取而代之的是,应使用RTFIFO在控制应用程序的时间关键循环和通信循环之间发送数据。此时,网络流可用于在控制应用程序和远程HMI的通信回路之间交换数据。

网络流旨在用于无损点对点通信。虽然这对于数据流和基于命令的应用程序非常有效,但是这使得建立任意N:1或多对多通信路径非常困难。这是许多客户端/服务器应用程序共有的要求。同样,由于流不保留读取后写入的最新值,因此在用于监视应用程序或更新HMI上的控件和指示器时,流通常更难使用。对于这些类型的应用程序,其他类型的通信方法通常更合适。有关如何为您的应用选择正确的通信方法的更多信息,请参考有关使用正确的网络协议的教程。 

最后,如果应用程序需要尽可能高的网络吞吐量,则可能希望使用TCP API代替网络流。使用TCP,可以最大程度地控制通过网络发送的数据,并允许您自定义通信,以便针对您的应用进行优化。同样,如果您使用网络流在同一LabVIEW应用程序上下文中的端点之间进行通信,则可能需要考虑使用队列以获得最佳性能。由于通信是在相同的内存上下文中进行的,因此队列将仅使用单个内存缓冲区。这将比网络流提供更好的性能,网络流依赖于两个端点缓冲区,而不管端点在何处托管。

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/221854.html

(0)
联系我们
联系我们
分享本页
返回顶部