我有多个线程处理事件。我想为每个事件分配一个纳秒时间戳。但它必须是一个独特的id。因此,在奇怪的情况下,两个事件到达使得它们将被分配相同的时间戳,我希望其中一个增加一纳秒。鉴于实际精度不是纳秒级,就系统的时间戳性质而言,这是可以的。
在一个帖子中,这是一个微不足道的问题。但是跨越多个线程,它变得更具挑战性。性能是绝对关键的,所以天真地同步典型的id生成器类型的东西的想法似乎会阻止太多。
是否有一些方法可以解决这个问题,只需要很少的锁定或没有锁定?
答案 0 :(得分:2)
为什么不将时间戳和唯一ID生成的问题分开?例如,标准模块Data.Unique
可以在IO
中提供全局唯一值,并且对于大多数用途而言应该足够快。或者,如果您需要更高级的东西,concurrent-supply包提供了一个高性能的并发唯一ID供应和纯接口。
也就是说,您可以使用POSIX monotonic clock来实现此目的,例如, clock包裹:
import Control.Monad
import qualified System.Posix.Clock as Clock
main :: IO ()
main = replicateM_ 100 $ do
time <- Clock.getTime Clock.Monotonic
print (Clock.sec time, Clock.nsec time)
答案 1 :(得分:2)
您可以使用两条信息作为唯一ID吗?如果是,请为每个线程分配一个唯一的id,并为每个事件记录纳秒时间戳和分配时间戳的线程的id。然后问题就减少到你在单线程情况下所做的任何事情,以保证时间戳的唯一性。初始化后根本没有同步。
答案 2 :(得分:1)
您可以使用atomicModifyIORef
来实现原子计数器。使用GHC,它是使用原子操作实现的,而不是锁。
import Data.IORef
import System.IO.Unsafe
counter :: IO Int
counter = unsafePerformIO $ newIORef 0
getUnique :: IO Int
getUnique = atomicModifyIORef counter $ \x -> let y = x + 1 in (y, y)
答案 3 :(得分:0)
在基于C语言中,我们通常使用原子计数器来完成此操作 - 不需要锁定。如果您还想要时间戳,那么这将是一个单独的值。我不确定Haskell,因为我不用它写(听起来很有趣)。
答案 4 :(得分:0)