我试图找到一些资源以获得最佳性能并通过消息传递进行扩展。我听说通过值而不是引用传递消息可以具有更好的可扩展性,因为它适用于 NUMA 样式设置并减少了对给定内存地址的争用。
我会假设基于值的消息传递仅适用于“较小”的消息。“更小”的定义是什么?在什么时候引用会更好?有人会以这种方式进行流处理吗?
我正在为这类问题寻找一些有用的提示或资源。
谢谢 :-)
PS 我在 C# 中工作,但我认为这对于这类设计问题并不重要。
我试图找到一些资源以获得最佳性能并通过消息传递进行扩展。我听说通过值而不是引用传递消息可以具有更好的可扩展性,因为它适用于 NUMA 样式设置并减少了对给定内存地址的争用。
我会假设基于值的消息传递仅适用于“较小”的消息。“更小”的定义是什么?在什么时候引用会更好?有人会以这种方式进行流处理吗?
我正在为这类问题寻找一些有用的提示或资源。
谢谢 :-)
PS 我在 C# 中工作,但我认为这对于这类设计问题并不重要。
杰里米的出色建议中增加了一些因素:
1)按值传递仅对小消息有效。如果数据在开始时有一个 [cache-line-size] 未使用区域以避免错误共享,那么您已经接近通过引用传递更有效的大小。
2) 更宽的队列意味着更多的空间被队列占用,影响内存使用。
3) 将数据复制到/复制出宽队列结构需要时间。除了移动数据时的实际 CPU 使用情况外,队列在复制期间保持锁定状态。这会增加队列的争用,并导致与队列宽度相关的整体性能下降。如果您的代码中存在任何潜在的死锁,那么长时间保持锁定将无济于事。
4)按值传递往往会导致特定于数据大小的代码,即。在编译时固定。除了令人讨厌的模板侵扰之外,这使得在运行时调整缓冲区大小等变得非常困难。
5) 如果消息是通过引用传递和 malloced/freed/newed/disposed/GC'd 的,这可能导致内存管理器的过度争用和频繁、浪费的 GC。我通常使用固定的消息池,在启动时分配,特别是为了避免这种情况。
6) 通过引用传递时,处理字节流可能会很尴尬。如果字节流的特点是频繁传递单个字节,则仅当字节被分块时,引用传递才有意义。这可能导致需要超时以确保及时将部分填充的消息分派到下一个线程。这引入了复杂性和延迟。
7) Pass-by-reference 设计本质上更容易泄漏。这可能导致测试时间延长和对 valgrind 的过量使用——一种特别痛苦的瘾,(我使用固定大小的消息对象池的另一个原因)。
8) 复杂的消息,例如。那些包含对其他对象的引用,如果按值传递,可能会导致所有权和生命周期管理的可怕问题。示例 - 服务器套接字对象具有对包含不同大小的缓冲区实例数组的缓冲区列表对象的引用(来自 IOCP 服务器的真实示例)。尝试按值传递..
9) 许多操作系统调用只能处理指针。你不能 PostMessage,(这是一个 Windows API,让你开心),甚至是一个 256 字节的结构,一次调用(你只有 2 个 wParam,lParam 整数)。设置异步回调的调用通常允许将“上下文数据”发送到回调 - 几乎总是只有一个指针。任何将要使用此类操作系统功能的应用程序几乎都被迫诉诸通过引用传递。
Jeremy Friesner 的评论似乎是最好的,因为这是一个新领域,虽然 Martin James 的观点也不错。我知道随着我们获得更多内核,微软正在研究他们未来内核的消息传递。
似乎有一个处理消息传递的框架,它声称比当前的 .Net 生产者/消费者泛型具有更好的性能。我不确定它将如何与 4.5 中的 .Net 数据流进行比较