関数の機能を説明できる人await
はいますか?
5 に答える
彼らは昨日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()に入りました。Sleeping 3
async task iteration 0
Task status: WaitingForActivation
Waiting for ENTER
async task iteration 1
async task iteration 2
async task iteration 3
async task iteration 4
async task iteration 5
async task iteration 6
async task iteration 7
async task iteration 8
async task iteration 9
Exiting仕事する()
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");
}
}
}