Высокопроизводительный уникальный идентификатор метки времени для нескольких потоков в Haskell - PullRequest
6 голосов
/ 29 января 2012

У меня есть несколько потоков обработки событий. Я хочу назначить наносекундную метку времени каждому событию. Это должен быть уникальный идентификатор, хотя. Итак, в нечетном случае, когда два события приходят так, что им будет назначена одна и та же временная метка, я хочу, чтобы одно из них было увеличено на одну наносекунду. Учитывая, что реальная точность не на наносекундном уровне, это нормально, если учитывать временную метку системы.

В одной теме это тривиальная проблема. Но через несколько потоков это становится более сложным. Производительность абсолютно критична, поэтому идея наивной синхронизации на типичном типе генератора идентификаторов кажется слишком сложной.

Есть ли подход, который решает это с минимальной блокировкой или без нее?

Ответы [ 5 ]

2 голосов
/ 30 января 2012

Не могли бы вы использовать две части информации в качестве уникального идентификатора?Если это так, присвойте каждому потоку уникальный идентификатор и запишите для каждого события наносекундную метку времени и идентификатор потока, который назначает метку времени.Тогда проблема сводится к тому, что вы сделали бы в однопоточном случае, чтобы гарантировать уникальность временных меток.И вообще без синхронизации после инициализации.

2 голосов
/ 29 января 2012

Почему бы не разделить проблемы создания временных меток и создания уникальных идентификаторов? Например, есть стандартный модуль Data.Unique, который обеспечивает глобальную поставку уникальных значений в IO и должен быть достаточно быстрым для большинства целей. Или, если вам нужно что-то более оригинальное, пакет concurrent-supply предлагает высокопроизводительный, параллельный источник уникальных идентификаторов с чистым интерфейсом.

Тем не менее, вы, вероятно, могли бы использовать для этой цели монотонные часы POSIX , например, используя. часы пакет:

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 голос
/ 29 января 2012

Вы можете использовать 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)
0 голосов
/ 29 января 2012
0 голосов
/ 29 января 2012

В языках на основе C мы обычно выполняем это с использованием атомарного счетчика - блокировка не требуется.Если вам нужна также временная метка, это будет отдельное значение.Я не уверен насчет Хаскелла, потому что я не пишу с ним (как бы интересно это ни звучало).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...