Zwei Gruppen von Threads abwechselnd laufen lassen?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

Hi,

ich habe folgendes Problem:

Ich habe einen Gruppe Threads A1-An und eine zweite Gruppe von Thread B1-Bm.
Diese beiden Gruppen formen nun eine Art Ring, dass heißt die Summe der Ausgaben der A Threads ist die Eingabe für die B Threads.
Die Ausgabe von denen ist wiederum die Eingabe für die A Threads.
Was ich nun haben möchte ist folgendes:
Es laufen erst alle A Threads, sobald alle A Threads fertig sind gehen sie ins wait und die B Thread starten.
Bs gehen ins wait, wenn alle im wait sind gehen die As wieder los. Rince and Repeat.

Ich brauche also irgendeine Form der Synchronisation zwischen den Threads. Die Frage ist nun welchen? (Bin halt kein Experte fürs Threading und bevor ich jetzt wilde Konstrukte anfange wollte ich erst eure Meinung einholen).

Ich würde mir also entweder einen Dual Semaphore oder eine Dualbarriere schreiben.
Bei beiden ist die Idee das die As das release für die Bs geben und die Bs das release für die As.
Die Frage ist nun:
Ist das eine gute Idee oder ist das total durchgeknallt?

Liebe Grüße,

p90
BlackJack

@p90: Muss man das unbedingt mit Threads (direkt) lösen? Ich würde immer erst einmal schauen ob es nicht mit ”higher level”-APIs wie `concurrent.futures` lösbar ist.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Alternativvorschlag:
  • Zwei weitere Threads CA und CB, die A bzw. B koordinieren.
  • 2 Queues CA->CB und CB->CA mit einer maximalen Größe von jeweils 1
Ein koordierender Thread C (CA oder CB) bekommt eine Eingabe über eine Queue QI (CB->CA falls C==CA, CA->CB falls C==CB), verteilt die Eingabe an die Gruppen Threads, wartet auf die Zwischenergebnisse, summiert sie und übergibt die Summe an eine Queue QO (CA->CB falls C==CA, CB->CA falls C==CB).

Durch die Queues ist sichergestellt dass entweder A oder B aktiv ist, ganz ohne seperate Synchronisationskonstrukte. Diese musst du auch nicht selbst erstellen, was selbst ein Experte mit hoher Wahrscheinlichkeit falsch machen würde.

Sollten A und B keine State haben, verwende concurrent.futures wie von BlackJack vorgeschlagen.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Falls es concurrent.Futures nicht sein soll - obwohl das besser wäre -, dann geht auch sowas hier, Python >=3.2 vorausgesetzt:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8

from queue import Queue
from threading import Barrier, Thread

def foo(queue):
    queue.put(...)

def bar(queue):
    some_value = queue.get()

def main():
    number_of_threads = 123
    foo_barrier = Barrier(number_of_threads)
    bar_barrier = Barrier(number_of_threads)
    queue = Queue()
    def driver():
        while True:
            foo(queue)
            foo_barrier.wait()
            bar(queue)
            bar_barrier.wait()
    for _ in range(number_of_threads):
        Thread(target=driver).start()

if __name__ == '__main__':
    main()
Ist ungetestet und dient nur zur Illustration. Immerhin spart man sich so ca. die Hälfte der Threads.
In specifications, Murphy's Law supersedes Ohm's.
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

Hallo,

erst mal Herzlichen Dank für die Tipps, future.concurrents kannte ich z.B. noch gar nicht.
Lese jetzt erstmal genau nach wie ich mit denen mein Problem umsetze und melde mich dann nochmal!

Vlt. noch ein Wenig Kontext um was es genau geht.
Und zwar möchte ich einen Sudoku Erzeuger/Löser schreiben. Dabei will ich das Sudoku aber auf Zellen und Gruppen abbilden um z.B. Samurai Sudoku
oder andere Formen auch direkt zu erschlagen. Die Idee ist dabei, dass ich erst die benötigten Zellen definiere, die dann in alle Gruppen packe zu der sie gehören und dann bi jeder Zelle sehe, welchen wert sie noch annehmen kann und sobald ich ihr einen Wert zuweise wird das durch alle Gruppen und Zellen propagiert.

Die Idee ist nun, die Zellen sind die A Threads, die Gruppen die B Threads. Wenn eine Zelle merkt, dass sie neue Informationen hat markiert sie isch als Tainted, hat diese Information alle B Threads erreicht laufen die los um zu sehen, ob sich aus dieser Information nun neue Information für andere Zellen bildet.
BlackJack

@p90: Und das kann man nicht ohne Threads lösen die das alles komplexer machen, aber auf CPython ziemlich sicher kein Stück schneller?
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Das Problem mit Threads zu lösen ist nur nicht schneller als ohne Threads, es ist garantiert signifikant langsamer.
Antworten