2012-01-29 15 views
6

Tengo múltiples eventos de procesamiento de subprocesos. Quiero asignar una marca de tiempo de un nanosegundo a cada evento. Sin embargo, debe ser una identificación única. Entonces, en el extraño caso de que lleguen dos eventos de modo que se les asigne la misma marca de tiempo, quiero que uno de ellos se incremente en un nanosegundo. Dado que la precisión real no está en el nivel de nanosegundos, está bien en cuanto a la naturaleza del sello de tiempo del sistema.Identificación única de marca de tiempo de alto rendimiento para varios subprocesos en Haskell

En un hilo, este es un problema trivial. Pero a través de múltiples hilos, se vuelve más desafiante. El rendimiento es absolutamente crítico, por lo que la idea de sincronizar ingenuamente en un tipo de generador de identificación típico parece bloquear demasiado.

¿Hay algún enfoque que resuelva esto con un bloqueo mínimo o sin bloqueo?

Respuesta

1

Puede usar atomicModifyIORef para implementar un contador atómico. Con GHC, se implementa utilizando operaciones atómicas, no bloqueos.

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

@ehird: por favor no realice cambios no triviales en mi publicación, publique un comentario en su lugar si tiene algo que agregar. –

+0

Lo siento, sentí que el cambio que estaba haciendo era bastante trivial, pero luego vi otros dos errores antes de guardar. Actualmente, 'getUnique' siempre devuelve' ⊥', y 'counter' puede insertarse en otras expresiones, duplicando la variable y rompiendo el código.Además, si se arreglaran ambos, entonces 'getUnique' tendría una fuga de espacio causada por la acumulación de thunk en las ejecuciones sucesivas. (Por cierto, el módulo estándar 'Data.Unique' en realidad ya proporciona esta API.) – ehird

+0

@ehird: Ese es exactamente el tipo de información que quería saber, gracias. –

2

¿Por qué no separar las preocupaciones de la marca de tiempo y la generación de ID única? Por ejemplo, está el módulo estándar Data.Unique, que proporciona un suministro global de valores únicos en IO y debe ser lo suficientemente rápido para la mayoría de los propósitos. O, si necesita algo más elegante, el paquete concurrent-supply ofrece un alto rendimiento, un único ID simultáneo con una interfaz pura.

Dicho esto, probablemente pueda usar el POSIX monotonic clock para este fin, usando p. Ej. clock el paquete:

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) 
+0

¿Tiene un rendimiento lo suficientemente alto? – augustss

+0

@augustss: ¿El reloj monotónico POSIX? No estoy seguro. Si no es lo suficientemente rápido, esa es otra buena razón para desacoplar la marca de tiempo y la generación de ID. – ehird

+0

@ehird se creará una identificación única en el momento b; en todos los casos, tendrá un valor más alto que una identificación única que se creó en el momento a (anterior). –

0

En lenguajes basados ​​en C, que había normalmente lograr esto utilizando un contador atómica - no se requiere ninguna cerradura. Si quieres una marca de tiempo también, ese sería un valor separado. No estoy seguro de Haskell porque no escribo con él (por muy interesante que parezca).

0
+0

¡Bienvenido a Stack Overflow! Si bien esto podría responder teóricamente a la pregunta, [sería preferible] (http://meta.stackexchange.com/q/8259) incluir aquí las partes esenciales de la respuesta y proporcionar el enlace de referencia. – oers

2

¿Podría utilizar dos elementos de información como identificación única? De ser así, proporcione a cada hilo una identificación única y registre para cada evento la marca de tiempo nanosegundo y la identificación del hilo que asigna la marca de tiempo. Luego, el problema se reduce a lo que hubiera hecho en el caso de un solo hilo para garantizar la singularidad de las marcas de tiempo. Y sin sincronización en absoluto después de la inicialización.

Cuestiones relacionadas