1

コルーチンを使用せずにこれを実行できるかどうか疑問に思っていました:

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、ColB、および CollC は UI スレッドで使用されます。GetAll を UI とは異なるスレッドで実行する必要があり、GetA()、GetB(param)、および GetC() を (並列ではなく) 次々に実行する必要があります。

結果は次のようになります (3 つの _refreshX がすべて true の場合):

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 await を使用してこれを達成しようとします。

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 はこの問題をどのように処理しますか?

4

2 に答える 2

3

C#5-を使用すると、これは非常に簡単asyncですawait。を使用してバックグラウンドスレッドで実行する必要のあるコードを実行し、Task.Run()次にawait、を使用してTask、非同期で完了を待機し、UIスレッドで再開します。

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;
    }
}
于 2012-10-14T14:47:53.240 に答える
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代わりに使用する必要がありました。

于 2012-10-14T02:50:05.793 に答える