2016-06-09 8 views
1

Wenn die Benutzeroberfläche in meinem C# Silverlight-Anwendung zu initialisieren, ich mache mehrere asynchrone Aufrufe an verschiedene Dienste. Während das Laden asynchron ist sehr schön und schnell, gibt es immer noch Zeiten, wenn ich brauche einen Schritt des Ladens, um am Ende zu passieren.Den Überblick über asynchrone Belastung und Thread-Sicherheit behalten?

Auf einigen Ansichten in der Vergangenheit hatte ich eine „Ladeliste“ Mechaniker mir zu helfen, den Überblick über Laden zu halten implementiert und garantieren die Reihenfolge der Aktionen, was auch immer wählerisch sind, wenn sie feuern. Hier ist ein sehr vereinfachtes Beispiel:

private List<string> _loadingList = new List<string>(); 

// Called to begin the loading process 
public void LoadData(List<long> IDs){ 
    foreach(long id in IDs){ 
     DoSomethingToLoadTheID(id); 
     _loadingList.Add(id.ToString()); 
    } 
} 

// Called every time an ID finishes loading 
public void LoadTheIDCompleted(object sender, ServiceArgs e){ 
    UseTheLoadedData(e); 

    _loadingList.Remove(id.ToString()); 
    if(_loadingList.Count == 0) 
     LoadDataFinally(); 
} 

// Must be called after all other loading is completed 
public void LoadDataFinally(){ 
    ImportantFinishingTouches(); 
} 

Das Ding funktioniert für meine Zwecke, und ich habe keine Probleme mit ihm noch erlebt. Aber ich bin nicht so zuversichtlich über meine Kenntnisse der Thread-Sicherheit, wie ich sein möchte, so möchte ich ein paar Fragen stellen:

  • Gibt es eine Möglichkeit diese Art der Sache kann vermasseln katastrophal?
  • Gibt es einen besseren Weg, um diese gleiche Funktionalität zu erreichen?

(I Visual Studio 2013 und .NET Framework bin mit 4.5.51209 und Silverlight 5,0)

Antwort

1

Gibt es eine Möglichkeit diese Art der Sache kann katastrophal vermasseln?

Je nachdem, was Sie tun, absolut. Zuerst greifen Sie von mehreren Threads auf List(of T) zu. Sie sollten stattdessen ConcurrentList<T> verwenden, da es threadsicher ist. Denken Sie daran, dass jede Klasse (einschließlich .NET-Framework-Komponenten), auf die von mehreren Threads zugegriffen/geändert wird, Thread-sicher sein muss. MSDN gibt an, welche Framework-Komponenten sind und welche nicht.

Gibt es einen besseren Weg, um dieselbe Funktionalität zu erreichen?

ich nicht überall in Ihrem Code sehen, wo mehrere Threads verwendet werden, aber ich nehme an, dass, was Sie versuchen zu tun:

  • Hier finden Sie eine Liste von IDs
  • Run einige lang~~POS=TRUNC oder CPU-gebundener Prozess für jede ID
  • entfernen, dass die ID aus der Liste der IDs

Je nach Art von dem, was Sie mit jeder ID tun, Der Ansatz kann anders sein. Zum Beispiel, wenn die Arbeit CPU-bound ist, dann können Sie Aufgaben verwenden/TPL:

// Using TPL 
var ids = new List<int>() {1, 2, 3, 4}; 
Parallel.ForEach(ids, id => DoSomething(id)); // Invokes DoSomething on each ID in the list in parallel 

oder wenn Sie eine fein abgestimmte Kontrolle der Ordnung, dass die Dinge ausführen ...

var ids = new List<int>() {1, 2, 3, 4}; 

TaskFactory factory = new TaskFactory(); 
List<Task> tasks = new List<Task>(); 

foreach (var id in ids) 
{ 
    tasks.Add(factory.StartNew(() => DoSomething(id))); // executes async and keeps track of the task in the list 
} 

Task.WaitAll(tasks.ToArray()); // waits till everything is done 

tasks.Clear(); 

foreach (var id in ids) 
{ 
    tasks.Add(factory.StartNew(() => DoSomethingElse(id))); // executes async and keeps track of the task in the list 
} 

Task.WaitAll(tasks.ToArray()); // Wait till all DoSomethingElse is done 

// etc. 

Jetzt Wenn die Arbeit, an der Sie arbeiten, IO-gebunden ist (z. B. Webservice-Aufrufe, bei denen Sie auf langsame Antworten warten müssen), sollten Sie in Asynchronous Programming with async and await (C#) schauen.

Es gibt viele Möglichkeiten, mit Multi-Threading umzugehen, und manchmal ist es auch Teil der Herausforderung, den richtigen Weg zu finden (async/abwarten vs. Aufgaben vs. Semaphoren vs. Hintergrundarbeiter vs.).

+0

Ja, ich habe das eigentliche Threading-Material in meinem Beispiel nicht verwendet, weil es sehr sperrig ist. Das Projekt verwendet WCF-Dienste und leider weiß ich nicht viel darüber, wie diese funktionieren, außer Sie starten sie mit einem Aufruf einer generierten * ServiceName * Async() -Methode, und Sie erhalten die Ergebnisse, indem Sie einen generierten * ServiceName * Completed abonnieren Veranstaltung. So sehr ich TPL verwenden möchte, bin ich mir nicht sicher, wie es in dieses Muster passen würde, das über die gesamte Anwendung verteilt ist. –

+0

Ich habe auch den Eindruck, dass Silverlight hat keinen Zugriff auf etwas im Namespace System.Collections.Concurrent, und soweit ich aus einer Google-Suche weiß, gibt es nicht so etwas wie eine ConcurrentList . –

+0

http://stackoverflow.com/questions/18396139/which-version-of-silverlight-supports-task-parallel-library – DVK