kann ich zwei Probleme mit Ihrem aktuellen Design sehen, die sich auf das Rennen Zustand öffnen Sie erwähnen:
1) mit der Abbruchbedingung (Timer eine Giftpille) gehen direkt an das Kind Schauspieler zu senden. Mit diesem Ansatz kann das Kind sicher auf einem separaten Thread (innerhalb des Dispatcher) beendet werden, während gleichzeitig eine Nachricht eingerichtet wurde, um zu ihm in dem UserActorRegistry
Aktor (auf einem anderen Thread innerhalb des Dispatcher) weitergeleitet zu werden.
2) Mit einem PoisonPill
, um das Kind zu beenden. A PoisonPill
ist für einen eleganten Stop, der ermöglicht, dass andere Nachrichten in der Mailbox zuerst verarbeitet werden. In Ihrem Fall werden Sie aufgrund von Inaktivität beendet, was darauf hindeutet, dass keine anderen Nachrichten bereits im Postfach vorhanden sind. Ich sehe eine PoisonPill
als falsch hier, weil in Ihrem Fall eine andere Nachricht nach der PosionPill
gesendet werden und diese Nachricht würde sicherlich verloren gehen, nachdem die PoisonPill
verarbeitet wird.
Also werde ich vorschlagen, dass Sie die Beendigung der inaktiven Kinder an die UserActorRegistry
delegieren, anstatt es in den Kindern selbst zu tun. Wenn Sie den Zustand der Inaktivität feststellen, senden Sie eine Nachricht an die Instanz UserActorRegistry
, die angibt, dass ein bestimmtes untergeordnetes Kind beendet werden muss. Wenn Sie diese Nachricht erhalten, beenden Sie dieses Kind über stop
statt eine PoisonPill
senden. Wenn Sie das einzelne Postfach der UserActorRegistry
verwenden, das seriell verarbeitet wird, können Sie sicherstellen, dass ein untergeordnetes Objekt nicht gleichzeitig terminiert wird, während Sie ihm gerade eine Nachricht senden.
Jetzt gibt es hier eine Komplikation, mit der Sie umgehen müssen. Stoppen eines Schauspielers ist asynchron. Wenn Sie also stop
auf einem Kind aufrufen, wird es möglicherweise nicht vollständig angehalten, wenn Sie eine DoPerUserWork
-Nachricht verarbeiten, und könnte daher eine Nachricht senden, die verloren geht, weil sie gerade gestoppt wird. Sie können dies lösen, indem Sie einen internen Status (eine Liste) beibehalten, der Kinder darstellt, die gerade angehalten werden. Wenn Sie ein Kind anhalten, fügen Sie dessen Namen zu dieser Liste hinzu und richten Sie dann DeathWatch
(über context watch child
) darauf ein. Wenn Sie das Ereignis Terminated
für dieses Kind erhalten, entfernen Sie seinen Namen aus der Liste der untergeordneten Kinder. Wenn Sie Arbeit für ein Kind erhalten, während sein Name in dieser Liste ist, wiederholen Sie es für die erneute Verarbeitung, möglicherweise bis zu einer maximalen Anzahl von Malen, um nicht für immer zu versuchen und erneut zu verarbeiten.
Dies ist keine perfekte Lösung; Es ist nur eine Identifizierung einiger Probleme mit Ihrem Ansatz und ein Stoß in die richtige Richtung, um einige von ihnen zu lösen. Lass mich wissen, wenn du den Code dafür sehen willst und ich werde etwas zusammenpeitschen.
bearbeiten
Als Antwort auf Ihre zweite Bemerkung. Ich glaube nicht, dass Sie in der Lage sein werden, ein Kind zu betrachten ActorRef
und sehen, dass es derzeit heruntergefahren wird, also die Notwendigkeit für diese Liste von Kindern, die gerade dabei sind, herunterzufahren. Sie könnten die Nachricht DoPerUserWork
so aufwerten, dass sie ein Feld numberOfAttempts: Int enthält, und dieses inkrementieren und zur erneuten Verarbeitung an self zurücksenden, wenn das Zielkind gerade geschlossen wird. Sie können dann numberOfAttempts verwenden, um zu verhindern, dass Sie für immer in die Warteschlange eingereiht werden und bei einer maximalen Anzahl von Versuchen anhalten. Wenn Sie sich bei DeathWatch
nicht sicher fühlen, können Sie den Elementen in der Liste der heruntergefahrenen untergeordneten Elemente eine Komponente für die Lebensdauer hinzufügen. Du könntest dann Gegenstände beschneiden, wenn du sie siehst, wenn sie in der Liste sind, aber zu lange dort waren.
Es wird einfacher, wenn Sie die Liste der untergeordneten Akteure explizit in einer Karte verwalten. Anschließend können Sie den Zeitüberschreitungen für untergeordnete Akteure signalisieren, indem Sie eine Ablaufnachricht an das übergeordnete Element senden, wodurch das übergeordnete Element das Kind anhält und die Karte bereinigt. Die Karte wird synchron (aus der Perspektive des übergeordneten Schauspielers) gehalten, so dass die Wettlaufbedingung verschwindet. – tariksbl
Das klingt sinnvoll. Ich muss auch die Karte verwenden, um die Kinderschauspieler nachzuschlagen, anstatt sie namentlich zu suchen, sonst könnte es Konflikte geben, in denen das Kind sterben soll, aber es existiert immer noch in Akkas Kinderkarte. Es ist verschwenderisch, eine separate Kindkarte zu pflegen, wenn Akka diese Karte schon hat. – Rich
Eine separate Karte scheint überflüssig zu sein. Mehr noch, wenn ich bedenke, dass ich oft zwei Karten, die zweite Indizierung von ActorRef, aufhalte, um den ersten zu reinigen, wenn ich ein Terminated erhalte. Ja, interessant, wäre glatt, um Kind() zu verwenden. – tariksbl