在这个伪代码块中:
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
是单个值,没有不变量。
答案 0 :(得分:3)
我建议从STM事务中进行I / O只是一个坏主意。
大概你想要的是避免两个线程同时进行数据库查找。我要做的是:
查看该项目是否已在缓存中。如果是,我们就完成了。
如果不是,请用&#34标记;我是这样做的&#34; flag,提交STM事务,从DB获取它,并执行第二个STM事务以将其插入缓存(并删除标志)。
如果该项目已被标记,则retry
该交易。这会阻塞调用线程,直到第一个线程从DB中插入值。