await
関数が何をするのか誰かが説明できますか?
await
関数が何をするのか誰かが説明できますか?
回答:
彼らは昨日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();
基本的に、async
andawait
キーワードを使用すると、メソッドの実行を、await
非同期メソッド呼び出しをマークするのすべての使用で停止し、非同期操作が完了すると再開するように指定できます。これにより、スレッドや結合を明示的に定義したり、アプリのメインスレッドをブロックしたりすることなく、アプリのメインスレッドでメソッドを呼び出し、複雑な作業を非同期で処理できます。
yield return
IEnumerableを生成するメソッドのステートメントにいくぶん似ていると考えてください。ランタイムがに達するとyield
、基本的にメソッドの現在の状態が保存され、生成された値または参照が返されます。次回IEnumerator.MoveNext()がリターンオブジェクト(ランタイムによって内部的に生成される)で呼び出されると、メソッドの古い状態がスタックに復元され、実行は、yield return
私たちが決して離れなかったかのように、次の行から続行されます。方法。このキーワードがない場合、IEnumerator型は、状態を格納し、反復要求を処理するためにカスタム定義する必要があります。メソッドは、実際には非常に複雑になる可能性があります。
同様に、としてマークされたメソッドにasync
は、少なくとも1つが必要await
です。でawait
、実行時には、次のメッセージを処理し、応答性のアプリを保つために、ランタイムのメッセージループに非同期呼び出し、およびアンワインドバックを行い、現在のスレッドの状態とコールスタックを保存します。非同期操作が完了すると、次のスケジューリングの機会に、非同期操作をアップするためのコールスタックがプッシュバックされ、呼び出しが同期しているかのように続行されます。
したがって、これら2つの新しいキーワードyield return
は、カスタム列挙型の生成を単純化するのと同じように、基本的に非同期プロセスのコーディングを単純化します。いくつかのキーワードと少しの背景知識があれば、従来の非同期パターンの紛らわしく、エラーが発生しやすい詳細をすべてスキップできます。これは、Winforms、SilverlightのWPFなどのほとんどすべてのイベント駆動型GUIアプリでは無効になります。
現在受け入れられている答えは誤解を招くものです。
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
終了仕事する()
await
ますか?これがUIスレッドから呼び出された場合、UIスレッドが3秒間ブロックされることを意味しますか?このモデルのアイデアは、そのようなことを避けることです。
.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のブログシリーズをお勧めします。
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");
}
}
}