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

Phi*_*sky 6 haskell stm unsafe-perform-io

在这个伪代码块中:

atomically $ do
  if valueInLocalStorage key
      then readValueFromLocalStorage key
      else do
        value <- unsafeIOToSTM $ fetchValueFromDatabase key
        writeValueToLocalStorage key value
Run Code Online (Sandbox Code Playgroud)

使用安全unsafeIOToSTM吗?文档说:

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

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

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

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

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

    key 是单个值,没有不变量可以打破.

Mat*_*hid 3

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

想必您想要的是避免两个线程同时进行数据库查找。我要做的是这样的:

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

  • 如果不是,则用“我正在获取此”标志对其进行标记,提交 STM 事务,从数据库中获取它,然后执行第二个 STM 事务将其插入到缓存中(并删除该标志)。

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