Bei der Evaluierung von Thread-Pool-Bibliotheken für Aufgaben mit kurzer Laufzeit ist mir aufgefallen, dass sie alle deutlich schlechter abschneiden als OpenMP. Die Hauptursache scheint darin zu liegen, dass andere Bibliotheken Schwierigkeiten haben, mehrere Threads gleichzeitig zu starten, während OpenMP das irgendwie schafft.
Um das Problem zu veranschaulichen, habe ich ein vereinfachtes parallel_for-Beispiel erstellt. Ich starte 8 Threads und lasse sie dann entweder mit std::condition_variable oder mit einem Spin-Look mit std::atomic warten, bis ihr Start signalisiert wird. Dadurch soll der Overhead beim Starten von Threads ausgeschlossen werden. Start- und Endzeiten pro Thread werden im Speicher protokolliert und dann zur Visualisierung in eine Datei geschrieben. Den gleichen Arbeitsaufwand parallelisiere ich auch mit OpenMP.
Die Ergebnisse sind unten zu sehen. Die Threads beginnen ihre Arbeit nicht zur gleichen Zeit, wenn eine reguläre Sperre oder eine Spin-Sperre verwendet wird, aber alle Threads beginnen ungefähr zur gleichen Zeit, wenn OpenMP verwendet wird.
Ich habe mit g++ -O3 -fopenmp -lm -std=c++20 main.cpp -o main kompiliert und das Experiment auf einer i5-10300H-CPU mit 8 Kernen (4 davon „echt“) ausgeführt.
import csv, matplotlib.pyplot as plt
def plot_log(filename):
with open(filename) as f:
rows = list(csv.DictReader(f))
thread_ids = [int(row["thread_id"]) for row in rows]
# convert to ms
start_times = [float(row["start"]) * 1e3 for row in rows]
end_times = [float(row["end"]) * 1e3 for row in rows]
# start time at 0
min_time = min(start_times)
start_times = [s - min_time for s in start_times]
end_times = [e - min_time for e in end_times]
for start, end, tid in zip(start_times, end_times, thread_ids):
plt.barh(tid, end - start, left=start)
plt.xlabel("Time [ms]")
plt.ylabel("Thread ID")
plt.yticks(range(len(thread_ids)))
plt.grid(axis="y", alpha=0.5)
plt.xlim([0, 2])
def main():
plt.figure(figsize=(10, 16))
for i, name in enumerate(["lock", "spin_lock", "omp"], 1):
plt.subplot(3, 1, i)
plot_log(f"log_{name}.csv")
plt.title(name)
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()
Bei der Evaluierung von Thread-Pool-Bibliotheken für Aufgaben mit kurzer Laufzeit ist mir aufgefallen, dass sie alle deutlich schlechter abschneiden als OpenMP. Die Hauptursache scheint darin zu liegen, dass andere Bibliotheken Schwierigkeiten haben, mehrere Threads gleichzeitig zu starten, während OpenMP das irgendwie schafft. Um das [url=viewtopic.php?t=26065]Problem[/url] zu veranschaulichen, habe ich ein vereinfachtes parallel_for-Beispiel erstellt. Ich starte 8 Threads und lasse sie dann entweder mit std::condition_variable oder mit einem Spin-Look mit std::atomic warten, bis ihr Start signalisiert wird. Dadurch soll der Overhead beim Starten von Threads ausgeschlossen werden. Start- und Endzeiten pro Thread werden im Speicher protokolliert und dann zur Visualisierung in eine Datei geschrieben. Den gleichen Arbeitsaufwand parallelisiere ich auch mit OpenMP. Die Ergebnisse sind unten zu sehen. Die Threads beginnen ihre Arbeit nicht zur gleichen Zeit, wenn eine reguläre Sperre oder eine Spin-Sperre verwendet wird, aber alle Threads beginnen ungefähr zur gleichen Zeit, wenn OpenMP verwendet wird. Ich habe mit g++ -O3 -fopenmp -lm -std=c++20 main.cpp -o main kompiliert und das Experiment auf einer i5-10300H-CPU mit 8 Kernen (4 davon „echt“) ausgeführt. [img]https://i.sstatic.net/nkblM3PN.png[/img]
def main(): plt.figure(figsize=(10, 16)) for i, name in enumerate(["lock", "spin_lock", "omp"], 1): plt.subplot(3, 1, i) plot_log(f"log_{name}.csv") plt.title(name) plt.tight_layout() plt.show()
Java 21 führte die leichte virtuelle Threads -API ein. Jedes Tutorial, auf das ich begegnet bin, beschreibt sie als AS oder mehr skalierbar als die gemeinsamen Plattform -Threads. Debatte zwischen...
Dieser Blogeintrag erwähnt Pakete könnten entweder mit PIP oder mit einem Paketmanager (APT, DNF usw.) installiert werden. Diese Mischung von Optionen kann zu unerwünschten Effekten auf das System...