RxPY - Parallelität mit Scheduler
Ein wichtiges Merkmal von RxPy ist die Parallelität, dh die parallele Ausführung der Aufgabe. Um dies zu erreichen, haben wir zwei Operatoren subscribe_on () und compare_on (), die mit einem Scheduler zusammenarbeiten und über die Ausführung der abonnierten Aufgabe entscheiden.
Hier ist ein Arbeitsbeispiel, das die Notwendigkeit von Subscibe_on (), Observ_on () und Scheduler zeigt.
Beispiel
import random
import time
import rx
from rx import operators as ops
def adding_delay(value):
time.sleep(random.randint(5, 20) * 0.1)
return value
# Task 1
rx.of(1,2,3,4,5).pipe(
ops.map(lambda a: adding_delay(a))
).subscribe(
lambda s: print("From Task 1: {0}".format(s)),
lambda e: print(e),
lambda: print("Task 1 complete")
)
# Task 2
rx.range(1, 5).pipe(
ops.map(lambda a: adding_delay(a))
).subscribe(
lambda s: print("From Task 2: {0}".format(s)),
lambda e: print(e),
lambda: print("Task 2 complete")
)
input("Press any key to exit\n")
Im obigen Beispiel habe ich zwei Aufgaben: Aufgabe 1 und Aufgabe 2. Die Ausführung der Aufgabe erfolgt nacheinander. Die zweite Aufgabe startet erst, wenn die erste Aufgabe erledigt ist.
Ausgabe
E:\pyrx>python testrx.py
From Task 1: 1
From Task 1: 2
From Task 1: 3
From Task 1: 4
From Task 1: 5
Task 1 complete
From Task 2: 1
From Task 2: 2
From Task 2: 3
From Task 2: 4
Task 2 complete
RxPy unterstützt viele Scheduler, und hier werden wir ThreadPoolScheduler verwenden. ThreadPoolScheduler versucht hauptsächlich, mit den verfügbaren CPU-Threads zu verwalten.
In dem Beispiel, das wir zuvor gesehen haben, werden wir ein Multiprozessor-Modul verwenden, das uns den cpu_count gibt. Die Anzahl wird an den ThreadPoolScheduler übergeben, der es schafft, die Aufgabe basierend auf den verfügbaren Threads parallel zum Laufen zu bringen.
Hier ist ein Arbeitsbeispiel -
import multiprocessing
import random
import time
from threading import current_thread
import rx
from rx.scheduler import ThreadPoolScheduler
from rx import operators as ops
# calculate cpu count, using which will create a ThreadPoolScheduler
thread_count = multiprocessing.cpu_count()
thread_pool_scheduler = ThreadPoolScheduler(thread_count)
print("Cpu count is : {0}".format(thread_count))
def adding_delay(value):
time.sleep(random.randint(5, 20) * 0.1)
return value
# Task 1
rx.of(1,2,3,4,5).pipe(
ops.map(lambda a: adding_delay(a)),
ops.subscribe_on(thread_pool_scheduler)
).subscribe(
lambda s: print("From Task 1: {0}".format(s)),
lambda e: print(e),
lambda: print("Task 1 complete")
)
# Task 2
rx.range(1, 5).pipe(
ops.map(lambda a: adding_delay(a)),
ops.subscribe_on(thread_pool_scheduler)
).subscribe(
lambda s: print("From Task 2: {0}".format(s)),
lambda e: print(e),
lambda: print("Task 2 complete")
)
input("Press any key to exit\n")
Im obigen Beispiel habe ich 2 Aufgaben und die cpu_count ist 4. Da die Aufgabe 2 ist und die bei uns verfügbaren Threads 4 sind, können beide Aufgaben parallel gestartet werden.
Ausgabe
E:\pyrx>python testrx.py
Cpu count is : 4
Press any key to exit
From Task 1: 1
From Task 2: 1
From Task 1: 2
From Task 2: 2
From Task 2: 3
From Task 1: 3
From Task 2: 4
Task 2 complete
From Task 1: 4
From Task 1: 5
Task 1 complete
Wenn Sie die Ausgabe sehen, wurden beide Aufgaben parallel gestartet.
Stellen Sie sich nun ein Szenario vor, in dem die Aufgabe größer als die CPU-Anzahl ist, dh die CPU-Anzahl 4 und die Aufgaben 5 sind. In diesem Fall müssten wir prüfen, ob ein Thread nach Abschluss der Aufgabe frei geworden ist, damit dies möglich ist der neuen Aufgabe zugewiesen, die in der Warteschlange verfügbar ist.
Zu diesem Zweck können wir den Operator watch_on () verwenden, der den Scheduler beobachtet, wenn Threads frei sind. Hier ist ein Arbeitsbeispiel mit compare_on ()
Beispiel
import multiprocessing
import random
import time
from threading import current_thread
import rx
from rx.scheduler import ThreadPoolScheduler
from rx import operators as ops
# calculate cpu count, using which will create a ThreadPoolScheduler
thread_count = multiprocessing.cpu_count()
thread_pool_scheduler = ThreadPoolScheduler(thread_count)
print("Cpu count is : {0}".format(thread_count))
def adding_delay(value):
time.sleep(random.randint(5, 20) * 0.1)
return value
# Task 1
rx.of(1,2,3,4,5).pipe(
ops.map(lambda a: adding_delay(a)),
ops.subscribe_on(thread_pool_scheduler)
).subscribe(
lambda s: print("From Task 1: {0}".format(s)),
lambda e: print(e),
lambda: print("Task 1 complete")
)
# Task 2
rx.range(1, 5).pipe(
ops.map(lambda a: adding_delay(a)),
ops.subscribe_on(thread_pool_scheduler)
).subscribe(
lambda s: print("From Task 2: {0}".format(s)),
lambda e: print(e),
lambda: print("Task 2 complete")
)
#Task 3
rx.range(1, 5).pipe(
ops.map(lambda a: adding_delay(a)),
ops.subscribe_on(thread_pool_scheduler)
).subscribe(
lambda s: print("From Task 3: {0}".format(s)),
lambda e: print(e),
lambda: print("Task 3 complete")
)
#Task 4
rx.range(1, 5).pipe(
ops.map(lambda a: adding_delay(a)),
ops.subscribe_on(thread_pool_scheduler)
).subscribe(
lambda s: print("From Task 4: {0}".format(s)),
lambda e: print(e),
lambda: print("Task 4 complete")
)
#Task 5
rx.range(1, 5).pipe(
ops.map(lambda a: adding_delay(a)),
ops.observe_on(thread_pool_scheduler)
).subscribe(
lambda s: print("From Task 5: {0}".format(s)),
lambda e: print(e),
lambda: print("Task 5 complete")
)
input("Press any key to exit\n")
Ausgabe
E:\pyrx>python testrx.py
Cpu count is : 4
From Task 4: 1
From Task 4: 2
From Task 1: 1
From Task 2: 1
From Task 3: 1
From Task 1: 2
From Task 3: 2
From Task 4: 3
From Task 3: 3
From Task 2: 2
From Task 1: 3
From Task 4: 4
Task 4 complete
From Task 5: 1
From Task 5: 2
From Task 5: 3
From Task 3: 4
Task 3 complete
From Task 2: 3
Press any key to exit
From Task 5: 4
Task 5 complete
From Task 1: 4
From Task 2: 4
Task 2 complete
From Task 1: 5
Task 1 complete
Wenn Sie die Ausgabe sehen, wird in dem Moment, in dem Aufgabe 4 abgeschlossen ist, der Thread an die nächste Aufgabe übergeben, dh Aufgabe 5, und dieselbe wird ausgeführt.