# Eine Forschleife mit Threads abarbeiten um es zu schneller zu machen. Ist das möglich?



## Damlo (9. Jun 2017)

Hallo zusammen,

ich bekomme von einer API Schnittstelle, die ich mit einem Index aufrufe, Werte.

Ich bekomme den Letzten Eintrag auch raus. Sagen wir mal, der wäre 420.555. (ist wirklich nur ein beispiel, könnten auch mehr Daten sein. Es werden auch täglich mehr Daten)

jetzt kann ich eine forschleife machen die in etwa so aussieht:

```
for(int i =0; i <= 420555;i++){
 url = new URl("https://irgendeineURL/"+ i);
 ...
}
```

diese läuft aber verflucht lange. ( Klar sind auch viele Einträge usw. die ich auslese aber mehrer Stunden möchte ich nicht immer warten. Muss sie öfters mal abgleichen)

habt ihr eine Idee, wie ich dies schneller machen könnte ? 
Ich habe da irgendwie an Threads gedacht. Aber da ich noch nie mit Threads gearbeitet habe und im Internet auch nichts in dieser Richtung gefunden habe, habe ich noch keine Idee. Wie ich das umsetzten könnte. Und bevor ich mir jetzt die "mühe" mache, mich da einzuarbeiten und nichts für diese Aufgabe ist. Wollte ich mal fragen ob es so überhaupt gehen würde?

Mit freundlichen Grüßen Damlo


----------



## mrBrown (9. Jun 2017)

Ja, das lässt sich ziemlich gut mit Threads parallelisieren 

Als Stichwort vllt ExecutorService


BTW, da du von mehrere Tagen sprichst, lassen sich die bisherige Ergebnisse nicht cachen?


----------



## JStein52 (9. Jun 2017)

mrBrown hat gesagt.:


> Ja, das lässt sich ziemlich gut mit Threads parallelisieren


Du solltest aber schon mal testen was du hier durch parallelisierung gewinnst. Der "Algorithmus" lässt sich natürlich schon gut parallelisieren aber das Problem scheint mir ja nicht so sehr CPU-bound als mehr IO-bound zu sein und die Frage ist ob es an irgendwelchen darunterliegenden Schichten nicht doch wieder serialisiert wird.


----------



## Thallius (9. Jun 2017)

Was ist denn das für eine Schwachsinns API?


----------



## mrBrown (9. Jun 2017)

JStein52 hat gesagt.:


> Du solltest aber schon mal testen was du hier durch parallelisierung gewinnst. Der "Algorithmus" lässt sich natürlich schon gut parallelisieren aber das Problem scheint mir ja nicht so sehr CPU-bound als mehr IO-bound zu sein und die Frage ist ob es an irgendwelchen darunterliegenden Schichten nicht doch wieder serialisiert wird.


Grad IO-Bound lässt sich doch gut parallelisieren wenns übers Netzwerk geht

Einmal so, einmal mit `parallel`

```
IntStream.range(0, max).mapToObj(i -> test()).collect(Collectors.joining());
```


```
private String test() {
    try {
        URL url = new URL("https://example.com/");
        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
        return reader.lines().collect(Collectors.joining());
    } catch (java.io.IOException e) {
        throw new UncheckedIOException(e);
    }
}
```

Ergebnis dürfte eindeutig sein:

```
Benchmark             Mode    Cnt           Score           Error  Units
MyBenchmark.parallel  avgt    9    352_107_740,398 ± 119462722,332  ns/op
MyBenchmark.serial    avgt    9  1_028_141_011,222 ±  77239561,461  ns/op
```


----------



## JStein52 (9. Jun 2017)

Im Prinzip ja, wenns dumm läuft warten aber 10 Threads bis ein Ergebnis nach dem anderen daher kommt. Deshalb mal verifizieren. Ich würde ja deinen Ansatz mit dem cachen favorisieren falls das machbar ist. Aber er schreibt ja davon dass er ab und zu mal abgleichen will, das klingt eher so als ob das eben nicht geht


----------



## mrBrown (9. Jun 2017)

JStein52 hat gesagt.:


> Im Prinzip ja, wenns dumm läuft warten aber 10 Threads bis ein Ergebnis nach dem anderen daher kommt. Deshalb mal verifizieren.


Naja, wäre dann trotzdem nicht langsamer, als wenn ein Thread 10 mal wartet.



JStein52 hat gesagt.:


> Ich würde ja deinen Ansatz mit dem cachen favorisieren falls das machbar ist. Aber er schreibt ja davon dass er ab und zu mal abgleichen will, das klingt eher so als ob das eben nicht geht



Kommt drauf an, wie die API funktioniert. Im Idealfall lassen sich mehrere zusammen abfragen und der Server unterstützt Caching, aber da können wir nur raten


----------



## JStein52 (9. Jun 2017)

mrBrown hat gesagt.:


> Naja, wäre dann trotzdem nicht langsamer, als wenn ein Thread 10 mal wartet


Das stimmt. Aber die Frage war wird es schneller. Die Antwort ist meiner Meinung nach: Wahrscheinlich schon, wenn du Pech hast aber auch nicht. Wir wissen zu wenig über die Daten, wo sie herkommen, wie sie dort entstehen, was damit gemacht wird. Irgendwas muss er ja auch mit tun sonst ist es sinnlos die zu holen.


----------



## Damlo (12. Jun 2017)

Also die Daten speicher ein in meiner Datenbank. Habe am Wochenende mal den ExecutorService ausprobiert. Es scheint etwas schneller zu laufen. Aber ich denke eher das es daran liegt, die Daten auf die Datenbank zu speichern. 

Ich habe in dem internen Forum mal nach gefragt, ob es eine Möglichkeit gibt weniger Anfragen zu stellen, aber bisher haben die es (noch) nicht vorgesehen sowas zu implementieren. Deswegen bleibt mir nichts anderes übrig als diese Abfragen los zu hauen. Ich habe trotzdem eine Zeit Gewinnung von ca 6 Stunden Erziehlt durch den ExecutorService.


----------



## mrBrown (12. Jun 2017)

Damlo hat gesagt.:


> Aber ich denke eher das es daran liegt, die Daten auf die Datenbank zu speichern.



Schmeiß den Profiler an und find raus woran es liegt 
Und selbst wenn das Speichern das Problem sein sollte, kann man da vermutlich noch optimieren.



Damlo hat gesagt.:


> Ich habe in dem internen Forum mal nach gefragt, ob es eine Möglichkeit gibt weniger Anfragen zu stellen, aber bisher haben die es (noch) nicht vorgesehen sowas zu implementieren. Deswegen bleibt mir nichts anderes übrig als diese Abfragen los zu hauen.


Wenns ein einfacher http-Server ist gibts doch bestimmt last-modified oder eTag oder sonstiges? Oder ändern sich jeden Tag alle bisherigen und es kommen neue dazu?


----------



## Xyz1 (12. Jun 2017)

Du greifst auf eine gemeinsame Quelle zu. Die Quelle wird wahrscheinlich schnell sein, das ist nicht das Problem. Die Übertragung wird langsam sein, bei mehreren parallelen Übertragungen wird eine Übertragung aber nicht langsamer werden, als wenn diese nacheinander geschehen. Das macht der Webbrowser auch. Also ein Pool mit fester Größe (10) wird eine Ersparnis einbringen. Mir fällt als Beispiel gerade nur ein RSS-Reader ein, der z. B. 100 Beiträge liest. Ich kann das später mal ausprobieren - wenn noch gewünscht.

Immer feststellen, was dort langsam ist - und ob man es umgehen kann.


----------



## Thallius (12. Jun 2017)

Vieleicht erklärst du uns einfach mal was du da eigentlich für daten holst und was du damit vorhast. Ich denke dein ganzes Konzept hat einen großen Fehler....


----------



## Damlo (12. Jun 2017)

Also ich greife auf die API von https://www.themoviedb.org zu. 

Ich möchte deren Filme auf eine Eigene Datenbank speichern. Heißt ich muss diese abfragen und bei mir speichern. 
Ich nutze Java Spring boot um sie mir wieder anzeigen zu lassen. Hab da ein paar "erweiterte" sachen geschrieben, die https://www.themoviedb.org nicht bietet. Aber für die Informationen der Filme / Serien / Personen Whatever, muss ich sie bei mir in der Datenbank speichern. 

Aber da man diese auch ändern kann auf dieser Seite. habe ich vorgesehen ein Vergleich zu schreiben, ob sich dort was geändert hat. Aber da es über 300.000 Einträge sind ( manche Id's gibt es nicht mehr, scheinen wohl gelöscht zu sein) dauert es halt. 



mrBrown hat gesagt.:


> Schmeiß den Profiler an und find raus woran es liegt


Wie genau meinst du das? wie kann ich das testen ? 

Ich bin zurzeit am überlegen, wie ich das Speichern Optimieren könnte. Zurzeit läuft es so, dass ich per For schleife über die ID's gehe. Die Url aufrufe, die JSON auslese, ein Objekt erzeuge, diese mit den JSON Inhalte fülle, aufbereite falls ich etwas anders haben möchte, speichere. Und das dann für alle ID's.


----------



## Thallius (12. Jun 2017)

Das

"We currently rate limit requests to 40 requests every 10 seconds. You can inspect the status of your limits by looking at the X-RateLimit response headers."

hast du aber schon gelesen oder?

Gruß

Claus


----------



## Joose (12. Jun 2017)

Damlo hat gesagt.:


> Ich bin zurzeit am überlegen, wie ich das Speichern Optimieren könnte. Zurzeit läuft es so, dass ich per For schleife über die ID's gehe. Die Url aufrufe, die JSON auslese, ein Objekt erzeuge, diese mit den JSON Inhalte fülle, aufbereite falls ich etwas anders haben möchte, speichere. Und das dann für alle ID's.



Meiner Meinung nach solltest du nur die Änderungen speichern was du eben zusätzlich bzw. anders anzeigen willst.
Die eigentlichen Daten würde ich immer von der Webseite lesen, damit ersparst du dir das Vergleichen und Abspeichern.


----------



## Damlo (12. Jun 2017)

ne, hatte ich noch nicht gelesen. 
Wenn ich das dann rauf rechne. Bei ca 400.000 Einträgen brauche ich also ca 28 Stunden. 
Um Sie einmalig alle zu laden... Dann brauche ich auch nichts "optimieren". Eher verschlechtern, da ich wahrscheinlich über meine 40 anfragen die 10 Sekunden komme


----------



## JStein52 (14. Jun 2017)

Damlo hat gesagt.:


> Eher verschlechtern, da ich wahrscheinlich über meine 40 anfragen die 10 Sekunden komme


Und ich sach noch .... irgendwo wird das Ganze wieder serialisiert/ausgebremst.


----------



## JStein52 (14. Jun 2017)

Ist bei dieser Schnittstelle das was heute die ID 4711 hat etwas anderes als das was morgen die ID 4711 hat ? Oder kommen neue ID's dazu und alte entfallen ?


----------



## JuKu (14. Jun 2017)

Ich denke die IDs sind gleich.
Aber diese Art und Weise, wie du die Daten holst, ist nicht besonders gut...
Die Api wurde auch nie dazu designed, um deren ganze Datenbank auszulesen.

Außerdem solltest du unbedingt die Lizenz beachten:
https://www.themoviedb.org/documentation/api/terms-of-use
https://www.themoviedb.org/documentation/api/terms-of-use
z.B. steht da drin, dass du nicht unnötig viel Traffic erzeugen und bei allen Daten ein Verweis auf diese Seiten mit angeben musst.
Ich denke nach 4.2.4 ist dein Use Case gar nicht erlaubt.


----------



## JStein52 (14. Jun 2017)

JuKu hat gesagt.:


> Ich denke die IDs sind gleich.


Wenn du meinst was ich denke dass du meinst bräuchte er ja den datensatz mit der ID 4711 nur ein einziges mal zu holen ?


----------



## JuKu (14. Jun 2017)

JStein52 hat gesagt.:


> Wenn du meinst was ich denke dass du meinst bräuchte er ja den datensatz mit der ID 4711 nur ein einziges mal zu holen ?



Das sehe ich genauso.
Es sei denn, es aktualisiert wirklich jemand die Daten - aber davon ist bei so einer Datenbank nicht wirklich auszugehen.
Man kann es ja auch einmal monatlich updaten.


----------

