具有同步子任务的异步父任务

时间:2012-10-13 15:09:22

标签: .net task-parallel-library

我想知道是否可以在不使用协同程序的情况下完成:

private void GetAll()
{
    if (_refreshA)
    {
        collA = new ObservableCollection(GetA<A>());
        _refreshA = false;
    }

    if (_refreshB)
    {
        collB = new ObservableCollection(GetB<B>(param))
        _refreshB = false;
    }

    if (_refreshC)
    {
        collC = new ObservableCollection(GetC<C>())
        _refreshC = false;
    }
}

CollA,CollB和CollC用于UI线程。我需要在不同于UI的线程上执行GetAll,我需要一个接一个地(不是并行)执行GetA(),GetB(param)和GetC()。

结果应该是(如果所有3 _refreshX都为真):

create new thread
execute GetA() on new thread
wait for data to arrive
update UI collection with new data
create new thread
execute GetB(param) on new thread
wait for data to arrive
update UI collection with new data
create new thread
execute GetC() on new thread
wait for data to arrive
update UI collection with new data

这只能用TPL完成,还是我还需要使用协同程序?

编辑:因为我错误地认为async await无法在.NET 4上使用,而且svick和Adam Robinson指出了这一点,我将尝试使用async等待实现此目的:

System.Diagnostics.Debug.WriteLine(string.Format("Loading data started. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));

IsBusy = true;
//Task.Factory.StartNew(() => GetDataBatch()); // UI is responsive
GetDataBatch(); // UI is not freezed (it is shown), but it is not responsive

System.Diagnostics.Debug.WriteLine(string.Format("Loading data completed. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));

private async Task GetAll()
{
    if (_refreshA)
    {
        collA = new ObservableCollection(await Task.Run(() => GetA<A>()));
        _refreshA = false;

        System.Diagnostics.Debug.WriteLine(string.Format("GetA items loaded. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));

    }

    if (_refreshB)
    {
        collB = new ObservableCollection(await Task.Run(() => GetB<B>(param)));
        _refreshB = false;

        System.Diagnostics.Debug.WriteLine(string.Format("GetB items loaded. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));
    }

    System.Threading.Thread.Sleep(10000);

    if (_refreshC)
    {
        collC = new ObservableCollection(await Task.Run(() => GetC<C>()));
        _refreshC = false;

        System.Diagnostics.Debug.WriteLine(string.Format("GetC items loaded. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));
    }
}

结果是:

Loading data started. Thread: 9, 15-Oct-12 02:35:00
Loading data completed. Thread: 9, 15-Oct-12 02:35:00
GetA items loaded. Thread: 9, 15-Oct-12 02:35:00
GetB items loaded.  Thread: 9, 15-Oct-12 02:35:01
GetC items loaded.  Thread: 9, 15-Oct-12 02:35:11

问题:UI未冻结(显示视图),但它也没有响应。例如,如果我将鼠标悬停在菜单项上,则不会发生任何事情。我有一个模板(忙模板),在数据加载过程中显示,它应该向用户显示正在发生的事情。此模板未显示,看起来没有足够的CPU时间来绘制自己。如果我使用此代码:

Task.Factory.StartNew(() => GetDataBatch()); // UI is responsive
//GetDataBatch(); // UI is not freezed (it is shown), but it is not responsive

然后UI响应,繁忙的数据模板显示在屏幕上,但问题是现在所有的收集数据都属于除UI以外的其他线程,所以我不能从UI线程对它们进行任何操作。

async await如何处理这个问题?

2 个答案:

答案 0 :(得分:3)

使用C#5 async - await,这很简单:运行需要使用Task.Run()在后​​台线程上运行的代码然后await { {1}},异步等待它在UI线程上完成并恢复:

Task

答案 1 :(得分:1)

void GetAll() {
    new Thread(() => {
        if (_refreshA) {
            var alist = GetA<A>();
            Dispatcher.Invoke(new Action(() => { collA = new ObservableCollection<A>(alist); }));
            _refreshA = false;
        }

        if (_refreshB) {
            var blist = GetB<B>(param);
            Dispatcher.Invoke(new Action(() => { collB = new ObservableCollection<B>(blist); }));
            _refreshB = false;
        }

        if (_refreshC) {
            var clist = GetC<C>();
            Dispatcher.Invoke(new Action(() => { collC = new ObservableCollection<C>(clist); }));
            _refreshC = false;
        }
    }).Start();
}

Dispatcher.Invoke保证在方法继续之前各自完成的操作。仅作比较,如果你想要并行执行它们,则需要使用Dispatcher.BeginInvoke代替。