¿Cuál es la mejor manera de obtener un conjunto de hash concurrente, cuando las operaciones de escritura son el exceso de operaciones de lectura?

Renjith KN:

He encontrado que podemos obtener un conjunto de hash concurrente usando newKeySet();o con la keySet(default value)de una ConcurrentHashMap. ¿Es esta la mejor manera de crear un conjunto de hilos de proceso seguro cuando las operaciones de escritura son el exceso de la operación de lectura.

He leído acerca CopyOnWriteArraySetparece que es mejor cuando la lectura es el exceso de escritura.

Da la bienvenida a todas las respuestas que nos pueden ayudar a saber un poco más sobre esto.

davidxxx:

ConcurrentHashMap.newKeySet()y ConcurrentHashMap.keySet()que el retorno de una KeySetViewdependen de la ConcurrentHashMapclase que se bloquea en la escritura sólo y únicamente la asignación de teclas preocupados por la escritura y no todo el mapa.
En consecuencia, las operaciones de lectura son rápidos pero escribir también (muy ligeramente más lento en los hechos).

CopyOnWriteArraySetque se basa en CopyOnWriteArrayListno bloquea para la lectura pero cerraduras para las operaciones de escritura. Como consecuencia de ello para garantizar la consistencia de la lectura simultánea de cada operación de escritura desencadena una copia de la matriz subyacente.
Así, en el caso de no pequeña colección ( 100elemento o más, por ejemplo), CopyOnWriteArraySetoperaciones de escritura deben ser más caro (bloqueo en toda la colección + copia de la matriz subyacente) que KeySetView(bloqueo sólo y únicamente la entrada en cuestión).

El CopyOnWriteArraySetjavadoc subraya ese punto:

  • Es el más adecuado para aplicaciones en las que fije los tamaños generalmente se mantienen pequeñas, las operaciones de sólo lectura superan enormemente las operaciones mutativas , y que necesita para evitar interferencias entre los hilos durante el recorrido.

  • operaciones mutativas (ADD, juego, eliminar, etc.) son caros, ya que por lo general implican la copia de toda la matriz subyacente


Este es un punto de referencia donde se compara el comportamiento tanto.
Los Set<String>s se inicializan con 100 elementos ( "0" a 99" de valor) en cada iteración.
Los 6 primeros métodos son operaciones de escritura (eliminar, añadir un nuevo elemento, sobrescribir un elemento existente).
Mientras que los 4 próximos métodos son operaciones de lectura ( iterate, contiene).

@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Threads(8)
public class SetBenchmark {

    private Set<String> keySetView;
    private Set<String> copyOnWriteArraySet;
    private Random random;

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(SetBenchmark.class.getSimpleName())
                                          .warmupIterations(5)
                                          .measurementIterations(5)
                                          .forks(1)
                                          .build();

        new Runner(opt).run();
    }

    @Setup(Level.Iteration)
    public void doSetup() {
        random = new Random(1);
        keySetView = ConcurrentHashMap.newKeySet();
        copyOnWriteArraySet = new CopyOnWriteArraySet<>();
        init(keySetView);
        init(copyOnWriteArraySet);

    }

    private void init(Set<String> set) {
        IntStream.range(0, 100)
                 .forEach(i -> {
                     final String string = String.valueOf((char) i);
                     set.add(string);
                 });

    }


    // Writing
    @Benchmark
    public void _1_keySetView_remove() {
        doRemove(keySetView);
    }

    @Benchmark
    public void _2_copyOnWriteArraySet_remove() {
        doRemove(copyOnWriteArraySet);
    }

    @Benchmark
    public void _3_keySetView_add_with_new_value() {
        doAddWithNewValue(keySetView);
    }

    @Benchmark
    public void _4_copyOnWriteArraySet_add_with_new_value() {
        doAddWithNewValue(copyOnWriteArraySet);
    }

    @Benchmark
    public void _5_keySetView_add_with_existing_value() {
        doAddWithExistingValue(keySetView);
    }

    @Benchmark
    public void _6_copyOnWriteArraySet_add_with_existing_value() {
        doAddWithExistingValue(copyOnWriteArraySet);
    }

    // Reading
    @Benchmark
    public void _7_keySetView_iterate() {
        String res = doIterate(keySetView);
    }

    @Benchmark
    public void _8_copyOnWriteArraySet_iterate() {
        String res = doIterate(copyOnWriteArraySet);
    }

    @Benchmark
    public void _9_keySetView_contains() {
        boolean res = doContains(keySetView);
    }

    @Benchmark
    public void _010_copyOnWriteArraySet_contains() {
        boolean res = doContains(copyOnWriteArraySet);
    }


    // Writing
    private void doRemove(Set<String> set) {
        set.remove(getRandomString());
    }

    private void doAddWithNewValue(Set<String> set) {
        set.add(getRandomString() + set.size());
    }

    private void doAddWithExistingValue(Set<String> set) {
        set.add(getRandomString());
    }

    // Reading
    private String doIterate(Set<String> set) {
        String result = "";
        for (String string : set) {
            result += string;
        }
        return result;
    }

    private boolean doContains(Set<String> set) {
        return set.contains(getRandomString());
    }

    // Random value with seed
    private String getRandomString() {
        return String.valueOf(random.nextInt(100));
    }

}

No es el resultado (puntuación más baja es mejor).

las operaciones de escritura:

Modo de referencia Cnt Puntuación de error Unidades 
SetBenchmark._1_keySetView_remove avgt 61.659 ns / op 
SetBenchmark._2_copyOnWriteArraySet_remove avgt 249,976 ns / op 

SetBenchmark._3_keySetView_add_with_new_value avgt 240,589 ns / op 
SetBenchmark._4_copyOnWriteArraySet_add_with_new_value avgt 30691,318 ns / op 

SetBenchmark._5_keySetView_add_with_existing_value avgt 84,472 ns / OP 
SetBenchmark. _6_copyOnWriteArraySet_add_with_existing_value avgt 473,592 ns / op

las operaciones de lectura:

Moda referencia Cnt Puntuación de error Unidades 
SetBenchmark._7_keySetView_iterate avgt 13603.012 ns / en 
SetBenchmark._8_copyOnWriteArraySet_iterate avgt 13626.146 ns / en 

SetBenchmark._9_keySetView_contains avgt 53.081 ns / en 
SetBenchmark._10_copyOnWriteArraySet_contains avgt 250.401 ns / en

Lectura son tan rápidos para las dos Setimplementaciones sólo para el iterador.
Y la escritura es mucho más lento para CopyOnWriteArraySeten todo caso, pero cuando add()un valor no existente, que es todavía peor.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=229589&siteId=1
Recomendado
Clasificación