跟踪异步加载与线程安全性?

时间:2016-06-09 17:13:50

标签: c# asynchronous thread-safety loading

在我的C#Silverlight应用程序中初始化UI时,我会对不同的服务进行几次异步调用。虽然异步执行所有加载非常好并且速度很快,但仍有时候我需要在最后发生加载的一些步骤。

在过去的一些观点中,我实施了一个“加载列表”机制,以帮助我跟踪加载,并保证在他们开火时任何行动的顺序。这是一个非常简单的例子:

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();
}

这件事适合我的目的,我还没有遇到任何问题。但是我对我对线程安全的了解并不像我想的那样自信,所以我想问几个问题:

  • 这种事情有什么办法可以造成灾难性的后果吗?
  • 有没有更好的方法来实现相同的功能?

(我使用的是Visual Studio 2013和.NET Framework 4.5.51209,以及Silverlight 5.0)

1 个答案:

答案 0 :(得分:1)

  

这种事情有什么办法可以造成灾难性的后果吗?

完全取决于你在做什么。首先,您从多个线程访问List(of T)。您应该使用ConcurrentList<T>,因为它是线程安全的。请记住,多个线程访问/修改的任何类(包括.NET框架组件)必须是线程安全的。 MSDN指示哪些框架组件是和不是。

  

有没有更好的方法来实现同样的功能?

我没有在你的代码中看到使用多个线程的任何地方,但我认为你要做的是:

  • 获取ID列表
  • 为每个ID运行一些长时间运行或CPU绑定的进程
  • 从ID列表中删除该ID

根据您对每个ID所做的事情的性质,方法可能会有所不同。例如,如果工作受CPU限制,那么您可以使用Tasks / 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

或者,如果您需要对事物执行的顺序进行细粒度控制......

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.

现在,如果您正在进行的工作是IO绑定(例如,在必须等待缓慢响应的情况下进行Web服务调用),您应该查看Asynchronous Programming with async and await (C#)

有很多方法可以处理多线程,有时候找出正确的方法是挑战的一部分(异步/等待与任务对比信号量与背景工作者对等等。)