2010-12-05 7 views
5

Versión corta: ¿es seguro usar ets:foldl para eliminar todos los registros ETS mientras se está iterando a través de ellos?Usando ets: foldl como pobre para cada uno de cada registro

Supongamos que una tabla ETS está acumulando información y ahora es el momento de procesarla. Se lee un registro de la tabla, se usa de alguna forma y luego se borra. (Además, suponga que la tabla es private, por lo que no hay problemas de concurrencia.)

En otro idioma, con una estructura de datos similar, puede usar un para ... cada bucle, procesar cada registro y luego eliminarlo del hash/dict/map/lo que sea. Sin embargo, el módulo ets no tiene foreach, como p. lists hace.

Pero esto podría funcionar:

1> ets:new(ex, [named_table]). 
ex 
2> ets:insert(ex, {alice, "high"}). 
true 
3> ets:insert(ex, {bob, "medium"}). 
true 
4> ets:insert(ex, {charlie, "low"}). 
true 
5> ets:foldl(fun({Name, Adjective}, DontCare) -> 
     io:format("~p has a ~p opinion of you~n", [Name, Adjective]), 
     ets:delete(ex, Name), 
     DontCare 
    end, notused, ex). 
bob has a "medium" opinion of you 
alice has a "high" opinion of you 
charlie has a "low" opinion of you 
notused 
6> ets:info(ex). 
[... 
{size,0}, 
...] 
7> ets:lookup(ex, bob). 
[] 

Es este el enfoque preferido? ¿Es al menos correcto y libre de errores?

Tengo una preocupación general sobre la modificación de una estructura de datos durante el procesamiento, sin embargo, el ets:foldl documentation implica que ETS está bastante cómodo con usted modificando registros dentro de foldl. Como esencialmente estoy limpiando la mesa, quiero estar seguro.

Estoy usando Erlang R14B con una tabla set, pero me gustaría saber si hay advertencias con cualquier versión de Erlang, o cualquier tipo de tabla también. ¡Gracias!

Respuesta

8

Su enfoque es seguro. La razón por la que es seguro es que ets:foldl/3 usa internamente ets:first/1, ets:next/2 y ets:safe_fixtable/2. Estos tienen la garantía que desea, es decir, que puede matar elementos y aún así obtener la poligonal completa. Consulte la sección CONCURRENCY de erl -man ets.

Para su retirada de todos los elementos de la tabla, hay un sencillo de una sola línea, sin embargo:

ets:match_delete(ex, '_'). 

aunque no funciona si usted quiere hacer el IO-formato para cada fila en la que Si su enfoque con foldl es probablemente más fácil.

+0

Gracias. La sección * Concurrencia * de la página de manual es exactamente lo que me perdí. Claramente dice que si usas 'safe_fixtable' entonces cada objeto se visita una vez. Y sí, en mi código real estoy, por supuesto, haciendo un procesamiento complejo de los datos antes de marcarlo esencialmente como "hecho" a través de ets: eliminar. ¡Aclamaciones! – JasonSmith

1

En casos como este alternaremos entre dos tablas o simplemente crearemos una nueva tabla cada vez que comencemos a procesar. Cuando queremos comenzar un ciclo de procesamiento, cambiamos los escritores para comenzar a usar la tabla alternativa o nueva, luego hacemos nuestro procesamiento y borramos o eliminamos la tabla anterior.

Hacemos esto porque de lo contrario podría haber actualizaciones concurrentes a una tupla que podríamos perder. Estamos trabajando con contadores simultáneos de alta frecuencia cuando utilizamos esta técnica.

+0

Eso es genial, ya que es bastante similar al mecanismo de recarga de código. Mi preocupación inicial, usar foldl como foreach, ahora está resuelta, y es bueno recordar cómo mantener los contadores de forma adecuada (que es lo que también estoy haciendo). ¡Gracias! – JasonSmith

Cuestiones relacionadas