memory 共享内存mmap - 共享内存与消息传递如何处理大型数据结构?




5 Answers

  • 是的,在这种情况下,共享状态可能更快。 但是,只有你可以放弃锁,这只有在绝对只读时才可行。 如果它“大多是只读”那么你需要一个锁(除非你设法写无锁结构,被警告它们甚至比锁更棘手),然后你很难让它表现得像快速作为一种良好的消息传递架构。

  • 是的,您可以编写一个“服务器进程”来共享它。 使用非常轻量级的流程,它不会比编写一个小API来访问数据更重要。 想象一个'拥有'数据的对象(在OOP意义上)。 以块为单位拆分数据以增强并行性(在DB循环中称为“分片”)有助于处理大型情况(或者如果数据存储在慢速存储中)。

  • 即使NUMA成为主流,每个NUMA单元仍然拥有越来越多的内核。 一个很大的区别是消息可以在两个内核之间传递,而锁必须从所有内核的缓存中刷新,将其限制为单元间总线延迟(甚至比RAM访问慢)。 如果有的话,共享状态/锁定变得越来越不可行。

简而言之....习惯于消息传递和服务器进程,这是风靡一时。

编辑 :重新回答这个答案,我想补充一下在Go的文档中找到的一个短语:

通过通信共享内存,不通过共享内存进行通信。

这个想法是:当你在线程之间共享一块内存时,避免并发访问的典型方法是使用锁来进行仲裁。 Go样式是使用引用传递消息,线程仅在接收消息时访问内存。 它依赖程序员纪律的某种程度; 但是会产生非常干净的代码,可以很容易地进行校对,因此调试相对容易。

优点是您不必在每条消息上复制大块数据,也不必像某些锁实现那样有效地清除缓存。 如果风格能够带来更高性能的设计,那还为时尚早。 (特别是因为当前的Go运行时在线程调度上有些天真)

共享内存消息队列 golang共享内存

在查看Go和Erlang的并发方法时,我注意到它们都依赖于消息传递。

这种方法显然减轻了对复杂锁的需求,因为没有共享状态。

但是,请考虑许多客户端希望对内存中的单个大型数据结构进行并行只读访问的情况 - 如后缀数组。

我的问题:

  • 使用共享状态会比消息传递更快并且使用更少的内存,因为锁是大多数不必要的,因为数据是只读的,只需要存在于一个位置?

  • 如何在消息传递上下文中处理此问题? 是否有一个访问数据结构的进程,客户端只需要顺序请求数据? 或者,如果可能的话,数据是否会被分块以创建几个保存块的进程?

  • 鉴于现代CPU和内存的架构,两种解决方案之间是否存在很大差异 - 即,共享内存可以由多个内核并行读取 - 这意味着没有硬件瓶颈可能会使两个实现大致执行相同的操作?




在Erlang中,所有值都是不可变的 - 因此在进程之间发送时不需要复制消息,因为它无论如何都无法修改。

在Go中,消息传递是按照惯例 - 没有什么可以防止你向某个人发送一个指针通过一个通道,然后修改指向的数据,只有约定,所以再一次没有必要复制消息。




请注意,您的问题在技术上是非敏感的,因为消息传递可以使用共享状态,因此我将假设您的意思是使用深度复制传递消息以避免共享状态(如Erlang目前所做的那样)。

使用共享状态会比消息传递更快并且使用更少的内存,因为锁是大多数不必要的,因为数据是只读的,只需要存在于一个位置?

使用共享状态会快得多。

如何在消息传递上下文中处理此问题? 是否有一个访问数据结构的进程,客户端只需要顺序请求数据? 或者,如果可能的话,数据是否会被分块以创建几个保存块的进程?

可以使用任何一种方法。

鉴于现代CPU和内存的架构,两种解决方案之间是否存在很大差异 - 即,共享内存可以由多个内核并行读取 - 这意味着没有硬件瓶颈可能会使两个实现大致执行相同的操作?

复制缓存不友好,因此会破坏多核上的可伸缩性,因为它会加剧对作为主内存的共享资源的争用。

最终,Erlang风格的消息传递是为并发编程而设计的,而关于吞吐量性能的问题实际上是针对并行编程的。 这是两个完全不同的主题,它们之间的重叠在实践中很小。 具体而言,延迟通常与并发编程上下文中的吞吐量同样重要,并且Erlang样式的消息传递是实现期望的延迟概要(即始终如一的低延迟)的好方法。 然后共享内存的问题不是读者和编写者之间的同步,而是低延迟内存管理。




什么是大型数据结构?

一个人大是另一个人小。

上周我与两个人交谈 - 一个人正在制作嵌入式设备,他用“大”这个词 - 我问他是什么意思 - 他说超过256 KB - 后来在同一个星期后一个人谈论媒体发布 - 他用过“大”这个词我问他是什么意思 - 他想了一下然后说“不适合一台机器”说20-100 TB

在Erlang术语中,“大”可能意味着“不适合RAM” - 因此,对于4 GB的RAM数据结构> 100 MBytes可能被认为是大的 - 复制500 MB的数据结构可能是个问题。 在Erlang中复制小数据结构(比如<10 MBytes)绝不是问题。

实际上,大型数据结构(即不适合一台机器的数据)必须在多台机器上进行复制和“条带化”。

所以我想你有以下几点:

小数据结构没有问题 - 因为它们很小,数据处理速度快,复制速度快等等(仅仅因为它们很小)

大数据结构是一个问题 - 因为它们不适合一台机器 - 所以复制是必不可少的。




通常是消息传递语言(这在erlang中特别容易,因为它有不可变的变量)优化了进程之间的实际数据复制(当然只有本地进程:你会想要明智地考虑你的网络分发模式),所以这不是这不是一个问题。




Related

memory concurrency erlang parallel-processing go