新しいC#待機機能は何をしますか?[閉まっている]


83

await関数が何をするのか誰かが説明できますか?





この質問が広すぎるとは思わないか、閉じる必要があります。1つのキーワードが何を意味するのかを尋ねています。(以前のバージョンはどういうわけか異なっていましたか?)
Panzercrisis 2016

回答:


62

彼らは昨日PDCでこれについて話しました

Awaitは、.NETのタスク(並列プログラミング)と組み合わせて使用​​されます。これは、.NETの次のバージョンで導入されるキーワードです。これにより、多かれ少なかれ、メソッドの実行を「一時停止」して、タスクの実行が完了するのを待つことができます。簡単な例を次に示します。

//create and run a new task  
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation);

//run some other code immediately after this task is started and running  
ShowLoaderControl();  
StartStoryboard();

//this will actually "pause" the code execution until the task completes.  It doesn't lock the thread, but rather waits for the result, similar to an async callback  
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return
dataTask.Start();
DataTable table = await dataTask;

//Now we can perform operations on the Task result, as if we're executing code after the async operation completed  
listBoxControl.DataContext = table;  
StopStoryboard();  
HideLoaderControl();

2
約束のC#形式は

12
Thread.Join()によく似ています。
Steve Guidi 2010年


20
完全を期すために、上記のコードはasyncキーワードで装飾されたメソッドでラップする必要があることを追加しましょう。このメソッドは、最初のawaitキーワードが検出されるとすぐに戻ります。
przemek 2010年

14
つまり、メソッドを「一時停止」することができますが、スレッドを一時停止またはブロックしないことに注意してください。
Matt Crinklaw-Vogt 2010

47

基本的に、asyncandawaitキーワードを使用すると、メソッドの実行を、await非同期メソッド呼び出しをマークするのすべての使用で停止し、非同期操作が完了すると再開するように指定できます。これにより、スレッドや結合を明示的に定義したり、アプリのメインスレッドをブロックしたりすることなく、アプリのメインスレッドでメソッドを呼び出し、複雑な作業を非同期で処理できます。

yield returnIEnumerableを生成するメソッドのステートメントにいくぶん似ていると考えてください。ランタイムがに達するとyield、基本的にメソッドの現在の状態が保存され、生成された値または参照が返されます。次回IEnumerator.MoveNext()がリターンオブジェクト(ランタイムによって内部的に生成される)で呼び出されると、メソッドの古い状態がスタックに復元され、実行は、yield return私たちが決して離れなかったかのように、次の行から続行されます。方法。このキーワードがない場合、IEnumerator型は、状態を格納し、反復要求を処理するためにカスタム定義する必要があります。メソッドは、実際には非常に複雑になる可能性があります。

同様に、としてマークされたメソッドにasyncは、少なくとも1つが必要awaitです。でawait、実行時には、次のメッセージを処理し、応答性のアプリを保つために、ランタイムのメッセージループに非同期呼び出し、およびアンワインドバックを行い、現在のスレッドの状態とコールスタックを保存します。非同期操作が完了すると、次のスケジューリングの機会に、非同期操作をアップするためのコールスタックがプッシュバックされ、呼び出しが同期しているかのように続行されます。

したがって、これら2つの新しいキーワードyield returnは、カスタム列挙型の生成を単純化するのと同じように、基本的に非同期プロセスのコーディングを単純化します。いくつかのキーワードと少しの背景知識があれば、従来の非同期パターンの紛らわしく、エラーが発生しやすい詳細をすべてスキップできます。これは、Winforms、SilverlightのWPFなどのほとんどすべてのイベント駆動型GUIアプリでは無効になります。


31

現在受け入れられている答えは誤解を招くものです。 await何も一時停止していません。まず第一に、それが唯一の方法としてマークまたはラムダで使用することができるasyncとは、返却 Taskまたはvoidあなたが持って気にしない場合はTask、この方法で実行中のインスタンスを。

これがイラストです:

internal class Program
{
    private static void Main(string[] args)
    {
        var task = DoWork();
        Console.WriteLine("Task status: " + task.Status);
        Console.WriteLine("Waiting for ENTER");
        Console.ReadLine();
    }

    private static async Task DoWork()
    {
        Console.WriteLine("Entered DoWork(). Sleeping 3");
        // imitating time consuming code
        // in a real-world app this should be inside task, 
        // so method returns fast
        Thread.Sleep(3000);

        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("async task iteration " + i);
                    // imitating time consuming code
                    Thread.Sleep(1000);
                }
            });

        Console.WriteLine("Exiting DoWork()");
    }
}

出力:

DoWork()に入りました。スリープ3
非同期タスク反復0
タスクステータス:WaitingForActivationENTERを
待機
非同期タスク反復1
非同期タスク反復2
非同期タスク反復3
非同期タスク反復4
非同期タスク反復5
非同期タスク反復6
非同期タスク反復7
非同期タスク反復8
非同期タスク反復9
終了仕事する()


1
また、発信者が実行できるタスクを提供する前に、発信者を3秒間ブロックすることも知っていawaitますか?これがUIスレッドから呼び出された場合、UIスレッドが3秒間ブロックされることを意味しますか?このモデルのアイデアは、そのようなことを避けることです。
Servy 2013

1
@Servyはい、それがポイントでした。実行のすべての段階を表示します。これは実際の例ではありません。
杏里

7
@Servyは私を荒らしているのですか?
杏里

2
いいえ。私はあなたがあなたの答えを改善するのを手伝おうとしています。
Servy 2013

2
@アンリ...ここでのあなたの努力に本当に感謝しています。どうもありがとう!!
Praveen Prajapati 2013

11

.NETでの非同期プログラミングに不慣れな人のために、これはあなたがよりよく知っているかもしれないシナリオの(完全に偽の)アナロジーです-JavaScript / jQueryを使用したAJAX呼び出し。単純なjQueryAJAX投稿は次のようになります。

$.post(url, values, function(data) {
  // AJAX call completed, do something with returned data here
});

結果をコールバック関数で処理する理由は、AJAX呼び出しが戻るのを待っている間は現在のスレッドをブロックしないためです。応答の準備ができたときにのみコールバックが発生し、その間に現在のスレッドが他のことを実行できるようになります。

さて、JavaScriptがawaitキーワードをサポートしている場合(もちろんサポートしていません(まだ!))、これで同じことを達成できます:

var data = await $.post(url, values);
// AJAX call completed, do something with returned data here

これはかなりクリーンですが、同期のブロッキングコードを導入したように見えます。しかし、(偽の)JavaScriptコンパイラーは、その後すべてを取得awaitしてコールバックに接続するため、実行時に2番目の例は最初の例と同じように動作します。

それはあなたに多くの作業を保存しているようには思えないかもしれませんが、それは例外処理と同期の状況のようなものになると、コンパイラが実際にやっている多くのあなたのために重い物を持ち上げるのを。詳細については、FAQに続いてStephenClearyのブログシリーズをお勧めします。


この偽のアナロジーに固執して(それは私を大いに助けたので、ありがとう!)、「後のすべて」とはどういう意味ですか?同じ関数(メソッド)の範囲内のすべてのみ?または、それ以降のすべてが、コールスタックに追加された可能性のあるものと同じですか?

2
「後のすべて」=メソッドの残りの部分。コンパイラーは、メソッドの残りの部分をコールバックとして効果的に書き直し、コントロールは現在のメソッドの呼び出し元にすぐに戻ります。
トッドメニエ2015年

1
ブリリアントトッド、説明ありがとうございます。他の人にも役立つと思います。

-2

Javaで実装する必要がある場合は、次のようになります。

/**
 * @author Ilya Gazman
 */
public abstract class SynchronizedTask{

    private ArrayList<Runnable> listeners = new ArrayList<Runnable>();

    private static final ThreadPoolExecutor threadPoolExecutor =  new ThreadPoolExecutor(6, 6, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1000));

    public final void await(Runnable listener){
        synchronized (this) {
            listeners.add(listener);
        }
    }

    public void excecute(){
        onExcecute();
        for (int i = listeners.size() - 1; i >= 0; i--) {
            Runnable runnable;
            synchronized (this) {
                runnable = listeners.remove(i);
            }
            threadPoolExecutor.execute(runnable);
        }
    }

    protected abstract void onExcecute();
}

アプリケーションは次のように使用します。

public class Test{
    private Job job = new Job();

    public Test() {
        craeteSomeJobToRunInBackground();
        methode1();
        methode2();
    }

    private void methode1(){
        System.out.println("Running methode 1");
        job.await(new Runnable() {

            @Override
            public void run() {
                System.out.println("Continue to running methode 1");
            }
        });
    }

    private void methode2(){
        System.out.println("Running methode 2");
    }

    private void craeteSomeJobToRunInBackground() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                job.excecute();
            }
        }).start();
    }

    private class Job extends SynchronizedTask{

        @Override
        protected void onExcecute() {
            try {
                Thread.sleep(1000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Job is done");
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.