安全使用unsafeIOToSTM从数据库中读取?

时间:2015-12-07 10:01:34

标签: haskell stm unsafe-perform-io

在这个伪代码块中:

atomically $ do
  if valueInLocalStorage key
      then readValueFromLocalStorage key
      else do
        value <- unsafeIOToSTM $ fetchValueFromDatabase key
        writeValueToLocalStorage key value

使用unsafeIOToSTM是否安全?文档说:

  • STM实施通常会多次运行事务,因此如果您的IO有任何副作用,您需要为此做好准备。

    基本上,如果一个事务失败,那是因为某个其他线程wroteValueToLocalStorage,并且当重试该事务时,它将返回存储的值,而不是再次从数据库中获取。

  • STM实施将中止已知无效并需要重新启动的事务。这可能发生在unsafeIOToSTM的中间,因此请确保您没有获取需要释放的任何资源(在中止事务时忽略异常处理程序)。例如,这包括使用Handles执行任何IO。如果出错,可能会导致随机死锁。

    这让我最担心。从逻辑上讲,如果fetchValueFromDatabase没有打开新连接(即使用现有连接),一切都应该没问题。我还缺少其他陷阱吗?

  • 当IO运行时,事务可能已经看到内存视图不一致。由于事务的实现方式,在整个程序中您期望为真的不变量在事务中可能不正确。通常这对程序员来说是不可见的,但是使用unsafeIOToSTM会暴露它。

    key是单个值,没有不变量。

1 个答案:

答案 0 :(得分:3)

我建议从STM事务中进行I / O只是一个坏主意。

大概你想要的是避免两个线程同时进行数据库查找。我要做的是:

  • 查看该项目是否已在缓存中。如果是,我们就完成了。

  • 如果不是,请用&#34标记;我是这样做的&#34; flag,提交STM事务,从DB获取它,并执行第二个STM事务以将其插入缓存(并删除标志)。

  • 如果该项目已被标记,则retry该交易。这会阻塞调用线程,直到第一个线程从DB中插入值。