首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有同步子任务的异步父任务

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

Stack Overflow用户
提问于 2012-10-13 15:09:22
回答 2查看 270关注 0票数 1

我在想,如果不使用协同机制,是否可以做到这一点:

代码语言:javascript
复制
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;
    }
}

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

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

代码语言:javascript
复制
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来完成吗,还是我也需要使用协同呢?

编辑:由于我有错误的印象,异步等待不能在.NET 4上使用,svick和Adam向我指出,我将尝试使用异步等待来实现这一点:

代码语言:javascript
复制
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));
    }
}

结果是:

代码语言:javascript
复制
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时间来绘制自己。如果我使用这个代码:

代码语言:javascript
复制
Task.Factory.StartNew(() => GetDataBatch()); // UI is responsive
//GetDataBatch(); // UI is not freezed (it is shown), but it is not responsive

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

异步等待如何处理这个问题?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-10-14 14:47:53

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

代码语言:javascript
复制
private async Task GetAll()
{
    if (_refreshA)
    {
        collA = new ObservableCollection(await Task.Run(() => GetA<A>()));
        _refreshA = false;
    }

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

    if (_refreshC)
    {
        collC = new ObservableCollection(await Task.Run(() => GetC<C>()));
        _refreshC = false;
    }
}
票数 3
EN

Stack Overflow用户

发布于 2012-10-14 02:50:05

代码语言:javascript
复制
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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12874369

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档