共享内存与消息传递如何处理大型数据结构? [英] How does shared memory vs message passing handle large data structures?

查看:214
本文介绍了共享内存与消息传递如何处理大型数据结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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

我的问题:


  • 使用共享状态会更快,内存而不是消息传递,因为数据是只读的,并且只需要存在于一个单独的位置,锁定通常是不必要的。


  • 问题在消息传递上下文中被接近?会不会有一个访问数据结构的进程,并且客户端只需要从中顺序请求数据呢?或者,如果可能的话,数据是否会被分块以创建多个进程来保存块?

  • 现在的CPU&内存,这两种解决方案之间有很大的区别 - 即共享内存可以被多个内核并行读取 - 这意味着没有硬件瓶颈,否则这两种解决方案都会大致执行相同的操作? >

解决方案


  • 。但是,只有当你可以放弃锁定时,只有在绝对只读的情况下才可行。如果它大部分是只读的,那么你需要一个锁(除非你设法写无锁结构,被警告它们甚至比锁更复杂),然后你很难让它的性能如下作为一个很好的消息传递体系结构很快。

  • 是的,你可以编写一个'服务器进程'来共享它。通过真正轻量级的流程,与编写小型API访问数据相比,这并不复杂。像一个对象(在OOP意义上)认为'拥有'数据。以块为单位分割数据以增强并行性(在数据库圈中称为分片)有助于在大的情况下(或者如果数据在缓存中)。 即使NUMA正在成为主流,每个NUMA单元仍然拥有越来越多的核心。最大的区别是消息只能在两个内核之间传递,而锁必须从所有内核的缓存中刷新,将其限制为单元间总线延迟(甚至比RAM访问更慢)。如果有的话,共享状态/锁定变得越来越不可行。 到消息传递和服务器进程,这是所有的愤怒。



    编辑:重新审视这个答案,我想添加关于Go文档:
    $ b


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


    这个想法是:当线程之间共享一块内存时,避免并发访问的典型方法是使用一个锁进行仲裁。 Go的风格是传递一个带有引用的消息,一个线程在接收消息时只访问内存。它依赖于程序员纪律的某种程度;但结果是非常干净的代码,可以很容易校对,所以调试起来相对容易。



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


    In looking at Go and Erlang's approach to concurrency, I noticed that they both rely on message passing.

    This approach obviously alleviates the need for complex locks because there is no shared state.

    However, consider the case of many clients wanting parallel read-only access to a single large data structure in memory -- like a suffix array.

    My questions:

    • Will using shared state be faster and use less memory than message passing, as locks will mostly be unnecessary because the data is read-only, and only needs to exist in a single location?

    • How would this problem be approached in a message passing context? Would there be a single process with access to the data structure and clients would simply need to sequentially request data from it? Or, if possible, would the data be chunked to create several processes that hold chunks?

    • Given the architecture of modern CPUs & memory, is there much difference between the two solutions -- i.e., can shared memory be read in parallel by multiple cores -- meaning there is no hardware bottleneck that would otherwise make both implementations roughly perform the same?

    解决方案

    • Yes, shared state could be faster in this case. But only if you can forgo the locks, and this is only doable if it's absolutely read-only. if it's 'mostly read-only' then you need a lock (unless you manage to write lock-free structures, be warned that they're even trickier than locks), and then you'd be hard-pressed to make it perform as fast as a good message-passing architecture.

    • Yes, you could write a 'server process' to share it. With really lightweight processes, it's no more heavy than writing a small API to access the data. Think like an object (in OOP sense) that 'owns' the data. Splitting the data in chunks to enhance parallelism (called 'sharding' in DB circles) helps in big cases (or if the data is on slow storage).

    • Even if NUMA is getting mainstream, you still have more and more cores per NUMA cell. And a big difference is that a message can be passed between just two cores, while a lock has to be flushed from cache on ALL cores, limiting it to the inter-cell bus latency (even slower than RAM access). If anything, shared-state/locks is getting more and more unfeasible.

    in short.... get used to message passing and server processes, it's all the rage.

    Edit: revisiting this answer, I want to add about a phrase found on Go's documentation:

    share memory by communicating, don't communicate by sharing memory.

    the idea is: when you have a block of memory shared between threads, the typical way to avoid concurrent access is to use a lock to arbitrate. The Go style is to pass a message with the reference, a thread only accesses the memory when receiving the message. It relies on some measure of programmer discipline; but results in very clean-looking code that can be easily proofread, so it's relatively easy to debug.

    the advantage is that you don't have to copy big blocks of data on every message, and don't have to effectively flush down caches as on some lock implementations. It's still somewhat early to say if the style leads to higher performance designs or not. (specially since current Go runtime is somewhat naive on thread scheduling)

    这篇关于共享内存与消息传递如何处理大型数据结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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