2016-04-11 8 views
1

Ich habe derzeit einige synchrone C++ - Code, der einige zeitaufwändige Aufgaben in einer sequenziellen Weise ausführt. Ich überlege, Boost-Coroutinen zu verwenden, um dies in parallele Aufgaben umzuwandeln. Der Kern der Tasks ist ein Aufruf einer externen Bibliothek, die entweder eine synchrone API (die sie gerade verwendet) oder eine asynchrone API bereitstellt, die regelmäßig abgefragt werden muss, um die Aktion auszuführen und festzustellen, ob sie abgeschlossen wurde . Die API ist nicht Thread-sicher, aber wenn die asynchrone Version verwendet wird, kann sie mehrere Anforderungen gleichzeitig verarbeiten, solange die Abruf-API selbst nicht gleichzeitig aufgerufen wird.Erzwingen Sie den Schlaf zwischen Koroutilausführungen

(Da ich keine Thread-Verschiebung möchte, scheint es, dass ich die Coroutine-API direkt verwenden sollte, anstatt die ASIO-Wrapper o.ä. zu verwenden, aber ich bin auch bereit, davon überzeugt zu werden 1.55 im Moment, so dass die Fiber-Bibliothek nicht verfügbar ist, aber es scheint auch für diese Verwendung Overkill.)

Meine Hauptfrage mit Coroutines im Moment ist, dass ich nicht sicher bin, wie Throttling bei der Abstimmung implementieren - Sagen Sie, dass ich 100 Aufgaben parallel ausführen muss; Ich möchte, dass es einen Polling-Durchlauf durch alle 100 Aufgaben durchführt und dann den Thread für eine bestimmte Zeit schläft. Einige der Aufgaben können früher abgeschlossen werden als andere, so dass später noch immer 40 Aufgaben pro Schleife abgefragt und dann die gleiche Zeit lang geschlafen werden. Ich möchte nicht, dass es zweimal hintereinander die gleiche Aufgabe ohne Zwischenschlaf abfragt.

+1

Was hält Sie davon ab, das zu codieren, was Sie beschrieben haben? Codiere die Coroutine, um nur dann nachzugeben, wenn sie schlafen will, und laufe dann einfach durch alle aktiven Coroutinen, schlafe und wiederhole sie. –

+0

Wahrscheinlich nur Ungewohntheit. Vielleicht ist das einfacher als ich angenommen habe. – Miral

Antwort

0

Ok, erwies sich als viel einfacher als ich dachte. Dies ist, was ich mit so weit am Ende habe:

typedef boost::coroutines::coroutine<void>::push_type coroutine; 
typedef boost::coroutines::coroutine<void>::pull_type yield_context; 
typedef std::vector<coroutine> coroutine_list; 

bool run_once_all(coroutine_list& coros) 
{ 
    bool pending = false; 
    for (auto& coro : coros) 
    { 
     if (coro) 
     { 
      coro(); 
      pending = pending || !coro.empty(); 
     } 
    } 
    return pending; 
} 

void run_all(coroutine_list& coros, 
      const boost::chrono::nanoseconds& idle_ns) 
{ 
    while (run_once_all(coros)) 
    { 
     boost::this_thread::sleep_for(idle_ns); 
    } 
} 

void run_all(coroutine_list& coros, yield_context& yield) 
{ 
    while (run_once_all(coros)) 
    { 
     yield(); 
    } 
} 

Die Idee ist, dass Sie ein coroutine_list machen, dann emplace_back Lambda-Funktionen mit Unterschrift void (yield_context&), dann run_all. Der erste ist für die oberste Ebene und der zweite ist für verschachtelte Coroutinen.

Scheint zu arbeiten, obwohl ich es noch nicht ein großes Training gegeben habe. Eigentlich ein bisschen überrascht ist so etwas in der Bibliothek noch nicht.