Haskell中ConcurrentHashMap的类比是什么?

fyc*_*cth 5 multithreading haskell servlets

更新:请记住,我刚刚开始学习Haskell

假设我们正在编写具有以下一般功能的应用程序:

  • 在启动时,它从外部源收集一些数据;
  • 这些数据是一组复杂的结构,包含列表,数组,整数,字符串等;
  • 在运行时,应用程序提供Web API(servlet),提供对数据的访问.

现在,如果应用程序是用Java编写的,我们可以使用静态ConcurrentHashMap对象来存储数据(代表Java类).因此,在启动期间,应用程序可以使用数据填充地图,然后servlet可以访问它,为客户端提供一些API.

如果应用程序将用Erlang编写,我们可以使用ETS/DETS来存储数据(作为本机Erlang结构).

现在的问题是:实现这种设计的Haskell方法是什么? 它不应该是DB,它应该是某种轻量级的内存存储器,它可以存储复杂的结构(Haskell本机结构),并且可以从不同的线程(servlet,Java-world实体交谈)访问.在Haskell中:没有像Java中那样的静态全局变量,没有Erlang中的ETS和OTP,所以如何以正确的方式完成(没有使用像Redis这样的外部解决方案)?

谢谢

更新:问题的另一个重要部分 - 因为Haskell没有(?)具有'全局静态'变量,那么实现这个'全局可访问'数据保持对象的正确方法是什么(比如,它是"stm-containers" ")?我应该在'main'函数中的某个地方初始化它,然后将它传递给每个REST API处理程序吗?或者还有其他更正确的方法吗?

Nik*_*kov 8

从您的问题不清楚客户端API是否会提供变异数据的方法.

如果不是(即,API只是关于查询),那么任何不可变数据结构都足够了,因为不可变数据的一个优点是可以安全地从多个线程访问它,并确保它不会改变.不需要锁的开销或其他策略来处理并发.您只需在初始化期间构造不可变数据,然后只查询它.为此,请考虑像"无序容器"这样的包.

如果您的API也将改变数据,那么您将需要可变数据结构,这些结构针对并发进行了优化."stm-containers"是一个包,提供那些.


Car*_*arl 5

首先,我假设你的意思是它需要可用于多个线程,而不是多个进程.(区别在于线程共享内存,进程没有.)如果这个假设是错误的,那么你的大部分问题都没有意义.

所以,第一个重点:Haskell具有可变数据结构.它们可以在线程之间轻松共享.这是一个小例子:

import Control.Concurrent
import Control.Monad

main :: IO ()
main = do
    v <- newMVar 0 :: IO (MVar Int)
    forkIO . forever $ do
        x <- takeMVar v
        putMVar v $! x + 1
    forM_ [1..10] $ \_ -> do
        x <- readMVar v
        threadDelay 100
        print x
Run Code Online (Sandbox Code Playgroud)

注意在将值放入时使用($!)MVar. MVars不强制评估其内容.确保一切正常运行有一些微妙之处.在了解Haskell的评估模型之前,您将获得大量空间泄漏.这就是为什么这类事情通常在一个处理所有细节的库中完成的部分原因.

鉴于此,第一步方法是仅存储某种地图MVar.除非它受到很多争论,否则它实际上具有相当不错的性能特性.

当它处于争用状态时,您有一个良好的后备辅助方法,尤其是在使用哈希映射时.这是条纹.不是在一个MVar中存储一个地图,而是在N个MVar中使用N个地图.查找的第一步是使用哈希来确定要查看的N个MV中的哪个.

有一些花哨的无锁算法,可以使用更细粒度的可变值来实现.但总的来说,它们需要大量的工程工作才能在性能上提高几个百分点,这在大多数用例中并不重要.