5

Ich verwende Simple Injector als meine IoC-Container. SimpleInjector verwendet this simple technique to handle mixed life style for Per Thread and Per Web RequestVerwenden von Abhängigkeiten zu mehreren Threads mit Parallel.ForEach

container.RegisterPerWebRequest<IWebRepository, Repository>(); 
container.RegisterLifetimeScope<IThreadRepository, Repository>(); 
container.Register<IRepository>(container.GetInstance<Repository>()); 

// Register as hybrid PerWebRequest/PerLifetimeScope. 
container.Register<Repository>(() => 
{ 
    Repository repository; 
    if (HttpContext.Current != null) 
     repository = (Repository)container.GetInstance<IWebRepository>(); 
    else 
     repository = (Repository)container.GetInstance<IThreadRepository>(); 

    return repository; 
}); 

Leider (und natürlich!), An anderer Stelle in meiner UnitOfWork Klasse dies mir ein Thema zu geben, wenn ich Parallel.ForEach verwenden und versuche, in mehrere Instanzen der Repository-Klasse als nur parallel zu nennen die zuerst der Fäden findet einen Wert in HttpContext.Current

using (TransactionScope scope = new TransactionScope()) 
{ 
    Parallel.ForEach(new List<IRepository>() { _repository1, _repository2 ... }, 
     (repository) => 
     { 
      repository.Commit(); 
     }); 
    scope.Complete(); 
} 

Nun, da ich die Frage fertig bin ich, dass ich wahrscheinlich für die nicht oder nur etwas dumm ... aber was zum Teufel sehen auszuschreiben bin gefragt. .. kann das gemacht werden? Kann eine einzelne Anfrage/Thread-Registrierung mehreren internen Threads zur Verfügung gestellt werden?

Antwort

7

Mit Abhängigkeitsinjektion versuchen Sie, das Wissen über die Lebensdauer von Objekten zu zentralisieren. Dieser zentrale Ort wird Composition Root genannt. Wenn Sie beginnen, Abhängigkeiten von einem Thread zum anderen zu übergeben, müssen diese Teile des Codes wissen, ob diese Abhängigkeiten sicher übergeben werden können. Zum Beispiel, sind diese Abhängigkeiten Thread-sicher? Können diese Abhängigkeiten in diesem neuen Kontext ausgeführt werden (z. B. außerhalb einer HTTP- oder WCF-Anforderung)? Dies kann in vielen Situationen trivial sein, verhindert jedoch, dass Sie diese Abhängigkeiten mit anderen Implementierungen ändern, da Sie sich jetzt daran erinnern müssen, dass in Ihrem Code eine Stelle vorhanden ist, an der dies geschieht, und Sie wissen müssen, welche Abhängigkeiten weitergegeben werden. Sie dezentralisieren dieses Wissen erneut, was es schwieriger macht, über die Korrektheit Ihrer DI-Konfiguration nachzudenken und es einfacher macht, den Container so zu konfigurieren, dass Ihr Code (im besten Fall) direkt ausfällt oder die Race-Bedingungen schwer zu debuggen sind (schlimmstenfalls)).

Es ist daher am sichersten, wenn alle neu gestarteten Threads ein neues Objektdiagramm erstellen, indem Sie den Container danach fragen. Übergeben Sie keine Abhängigkeiten (dh Instanzen, die vom Container verwaltet und injiziert werden) von einem Thread an den anderen.

In Ihrem Fall scheinen Sie sogar Probleme zu haben, da Ihre Repositories anscheinend eine Beziehung zum http-Kontext haben, da sie nicht auf andere Threads übertragbar sind. In diesem Fall ist es ziemlich einfach: Tun Sie das nicht ;-)

Dies bedeutet nicht, dass Sie Multi-Threading nicht durchführen können, um die Leistung in irgendeiner Weise zu beschleunigen. Sie müssen jedoch sicherstellen, dass diese Operation keine Abhängigkeiten von einem Thread zu einem Thread verschiebt, oder wenn sie dies tun; Stellen Sie sicher, dass sich dieser Code (in Ihrem Fall Parallel.ForEach) im Kompositionswurzel Ihrer Anwendung befindet, da dies der einzige Ort ist, der wissen/kann, ob dieser Vorgang sicher ausgeführt werden kann.

In Ihrem speziellen Fall finde ich es jedoch ziemlich gruselig, dass Sie über mehrere Threads committieren. Sollte das Commit dieser Arbeitseinheit nicht atomar sein? Sind Sie sicher, dass diese Festschreibung immer noch atomar ist, wenn Sie die Repository-Commits für verschiedene Threads ausführen? Was passiert, wenn eines der Commits fehlschlägt, andere jedoch erfolgreich sind? Wie rollst du die bereits erfolgreichen Operationen zurück? Ich denke, Sie können diese Probleme lösen (und Sie haben es vielleicht schon getan), aber eine solche Lösung fügt dem System eine Menge zusätzlicher Komplexität hinzu. Sie müssen sich ernsthaft fragen, ob die Leistungsverbesserung tatsächlich die zusätzliche Komplexität kompensiert, die Sie dem System hinzugefügt haben.

Weitere Informationen zum Arbeiten mit Abhängigkeitsinjektion in Multithread-Anwendungen finden Sie unter here.

Verwandte Themen