Utworzyłem 1 milion węzłów Neo4j w partiach po 10000, każda partia we własnej transakcji. Dziwne jest to, że zrównoleglenie tego procesu z wykonywaniem wielowątkowym nie miało żadnego pozytywnego wpływu na wydajność. To tak, jakby transakcje w różnych wątkach blokowały się nawzajem.

Oto fragment kodu Scali, który testuje to za pomocą równoległych kolekcji:

import org.neo4j.kernel.EmbeddedGraphDatabase

object Main extends App {

    val total = 1000000
    val batchSize = 10000

    val db = new EmbeddedGraphDatabase("neo4yay")

    Runtime.getRuntime().addShutdownHook(
        new Thread(){override def run() = db.shutdown()}
    )

    (1 to total).grouped(batchSize).toSeq.par.foreach(batch => {

        println("thread %s, nodes from %d to %d"
            .format(Thread.currentThread().getId, batch.head, batch.last))

        val transaction = db.beginTx()
        try{
            batch.foreach(db.createNode().setProperty("Number", _))
        }finally{
            transaction.finish()
        }
    })
}

A oto wiersze build.sbt potrzebne do zbudowania i uruchomienia go:

scalaVersion := "2.9.2"

libraryDependencies += "org.neo4j" % "neo4j-kernel" % "1.8.M07"

fork in run := true

Można przełączać się między trybami równoległymi i sekwencyjnymi, usuwając i dodając wywołanie .par przed zewnętrznym foreach. Dane wyjściowe konsoli wyraźnie pokazują, że wykonanie .par jest rzeczywiście wielowątkowe.

Aby wykluczyć możliwe problemy ze współbieżnością w tym kodzie, wypróbowałem również implementację opartą na aktorach, z mniej więcej takim samym wynikiem (odpowiednio 6 i 7 sekund dla wersji sekwencyjnej i równoległej).

Więc pytanie brzmi: czy zrobiłem coś źle, czy to jest ograniczenie Neo4j? Dziękuję!

4
Oleg Mirzov 26 wrzesień 2012, 00:54

2 odpowiedzi

Najlepsza odpowiedź

Głównym problemem jest to, że twój tx dociera mniej więcej w tym samym czasie. A zatwierdzenia transakcji to serializowane zapisy w dzienniku transakcji. Jeśli zapisy byłyby przeplatane w czasie, a rzeczywiste tworzenie węzła byłoby droższym procesem, przyspieszyłoby to.

4
Michael Hunger 28 wrzesień 2012, 02:58

Wstawianie wsadowe nie działa z wieloma gwintami. Z dokumentacji neo4j:

Zawsze wykonuj wstawianie wsadowe w jednym wątku (lub używaj synchronizacji, aby tylko jeden wątek naraz miał dostęp do programu wsadowego) i wywołaj zamknięcie po zakończeniu.

Wkładka wsadowa Neo4j

2
Jan 27 wrzesień 2012, 13:41