Parallele Abfragen in Kotlin zur Automatisierung der Datenerfassung

Hallo, alle miteinander! In meiner Arbeit benutze ich Kotlin oft zur Automatisierung. Meine Tätigkeit steht nicht in direktem Zusammenhang mit der Programmierung, aber Kotlin vereinfacht die Arbeitsaufgaben erheblich.





Vor kurzem war es notwendig, Daten von ziemlich großer Größe zu sammeln, um die Analyse durchzuführen. Deshalb habe ich beschlossen, ein kleines Skript zu schreiben, um die Daten abzurufen und in Excel zu speichern. Es gab keine Probleme mit dem letzten Punkt - ich las über Apache POI, nahm einige Beispiele aus der offiziellen Dokumentation und modifizierte sie für mich. Gleiches gilt nicht für Internetanfragen.





Die Quelle wurde in Stapeln von json zurückgegeben, und es war notwendig, diese "Stapel" irgendwie schnell zu sammeln, sie in Text umzuwandeln und eine Tabelle in eine Datei zu schreiben.





Asynchrone Methode

Ich beschloss, mit einer einfachen Asynchronisation zu beginnen. Nachdem ich mich ein wenig in HttpUrlConnection umgesehen hatte, schickte ich es dorthin, wo es hingehört, und ersetzte es durch HttpClient aus Java.





Für Tests habe ich den Dienst https://jsonplaceholder.typicode.com/ verwendet , der mir von einem bekannten Entwickler vorgeschlagen wurde. Ich habe einen Link gespeichert, der Json mit Kommentaren zu einer Variablen ausgibt, um keine Tests zu duplizieren und zu starten.





const val URL = "https://jsonplaceholder.typicode.com/comments"
      
      



Die Funktion war bereit und funktionierte sogar. Die Daten kamen herein.





fun getDataAsync(url: String): String? {
    val httpClient = HttpClient.newBuilder()
        .build()
    val httpRequest = HttpRequest.newBuilder()
        .uri(URI.create(link)).build()

    return httpClient.sendAsync(httpRequest, BodyHandlers.ofString())
        .join().body()
}
      
      



Jetzt musste die Arbeitsgeschwindigkeit überprüft werden. Mit MeasureTimeMillis bewaffnet, habe ich den Code ausgeführt.





val asyncTime = measureTimeMillis { 
    val res = (1..10)
        .toList()
        .map {getDataAsync("$URL/$it")}
    res.forEach { println(it) }
}
println("   $asyncTime ")
      
      



Alles hat so funktioniert, wie es sollte, aber ich wollte es schneller. Nach einigem Stöbern im Internet stieß ich auf eine Lösung, bei der Aufgaben parallel ausgeführt werden.





Parallele Karte

, . , , .





suspend fun <A, B> Iterable<A>.pmap(f: suspend (A) -> B): List<B> =
    coroutineScope {
        map { async { f(it) } }.awaitAll()
    }
      
      



, ( Iterable) pmap, . A. async , .awaitAll() . suspend, .





, , - .





val parmapTime = measureTimeMillis {
    runBlocking {
        val res = (1..10)
            .toList()
            .pmap { getDataAsync("$URL/$it") }
        println(mapResult)
    }
}
println(" pmap $parmapTime ")
      
      



- 1523, . map async, .





Parallel Map v 2.0

, , .





suspend fun <T, V> Iterable<T>.parMap(func: suspend (T) -> V): Iterable<V> =
    coroutineScope {
        map { element -> 
            async(Dispatchers.IO) { func(element) } 
        }.awaitAll() 
    }

val parMapTime = measureTimeMillis {
    runBlocking {
        val res = (1..10)
            .toList()
            .parMap { getDataAsync("$URL/$it") }
    }
    println(res)
}
println(" map  $parMapTime ")
      
      



Dispatchers.IO 2 ~ 610 . ! ( , excel ..) . , - .





Java ParallelStream

, stackowerflow parallelStream. , IDEA.





val javaParallelTime = measureTimeMillis { 
    val res = (1..10).toList()
        .parallelStream()
        .map { getDataAsync("$URL/$it") }
    res.forEach { println(it) }
}
println("Java parallelSrtream  $javaParallelTime ")
      
      



, . , . stream . , , , "" , Json.





, - , async . .





Die Ergebnisse sind in der folgenden Tabelle aufgeführt. Für mich selbst habe ich mich definitiv entschlossen, asynchron zu warten . Hauptsächlich natürlich wegen der einfacheren Fehlerbehandlung. Und hier besteht keine Notwendigkeit, über die Coroutinen hinauszugehen.





Methode





Zeit (ms)





Asynchrone Methode





1487





Pmap-Implementierung aus dem Web





1523





Meine Option ist parallelMap





610





Java.parallelStream





578





In Zukunft gibt es Überlegungen, dies in einer kleinen Bibliothek zu arrangieren und für persönliche Zwecke zu verwenden und natürlich alles vom "Hindu-Code" in den menschlichen Code umzuschreiben, solange es genügend Möglichkeiten gibt. Und dann lade alles auf vds hoch.





Ich hoffe, meine Erfahrung ist für jemanden nützlich. Ich würde mich über konstruktive Kritik und Beratung freuen! Danke an alle








All Articles