누구든지이 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
및 await
키워드를 사용하면 메서드 실행이의 모든 사용에서 중지되도록 지정하여 await
비동기 메서드 호출을 표시 한 다음 비동기 작업이 완료되면 다시 시작 하도록 지정할 수 있습니다 . 이를 통해 앱의 기본 스레드에서 메서드를 호출하고 스레드 및 조인을 명시 적으로 정의하거나 앱의 기본 스레드를 차단할 필요없이 복잡한 작업을 비동기 적으로 처리 할 수 있습니다.
yield return
IEnumerable을 생성하는 메서드 의 문과 다소 유사하다고 생각하십시오 . 런타임이에 도달 yield
하면 기본적으로 메서드의 현재 상태를 저장하고 산출되는 값 또는 참조를 반환합니다. 다음에 IEnumerator.MoveNext ()가 반환 객체 (런타임에 의해 내부적으로 생성됨)에서 호출되면 메서드의 이전 상태가 스택에 복원되고 다음 줄에서 실행이 계속됩니다 yield return
. 방법. 이 키워드가 없으면 IEnumerator 유형은 상태를 저장하고 반복 요청을 처리하기 위해 사용자 정의해야합니다. 메서드는 실제로 매우 복잡해질 수 있습니다.
마찬가지로,로 표시하는 방법은 async
적어도 하나 있어야 await
. 온 await
, 현재의 thread의 상태와 호출 스택을 절약 할 수 런타임은, 비동기 호출, 다음 메시지를 처리하고 응답 응용 프로그램을 유지하는 런타임의 메시지 루프에 풀림 등을 확인합니다. 비동기 작업이 완료되면 다음 예약 기회에 비동기 작업을위한 호출 스택이 다시 푸시되어 호출이 동기식 인 것처럼 계속됩니다.
따라서이 두 가지 새로운 키워드는 기본적으로 yield return
사용자 지정 열거 형 생성을 단순화 한 것처럼 비동기 프로세스의 코딩을 단순화합니다. 몇 가지 키워드와 약간의 배경 지식 만 있으면 기존 비동기 패턴의 혼란스럽고 종종 오류가 발생하기 쉬운 세부 정보를 모두 건너 뛸 수 있습니다. 이는 Silverlight의 WPF 인 Winforms와 같은 거의 모든 이벤트 기반 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
작업 상태 : WaitingForActivation
ENTER
비동기 작업 반복 1
비동기 작업 반복 2
비동기 작업 반복 3
비동기 작업 반복 4
비동기 작업 반복 5
비동기 작업 반복 6
비동기 작업 반복 7
비동기 작업 반복 8
비동기 작업 반복 9
종료 일해()
await
있습니까? 이것이 UI 스레드에서 호출되면 3 초 동안 UI 스레드를 차단한다는 의미입니까? 이 모델의 아이디어는 그런 일을 피하는 것입니다.
.NET에서 비동기 프로그래밍을 처음 접하는 사람을 위해 더 친숙 할 수있는 시나리오의 (완전히 가짜) 비유가 있습니다. JavaScript / jQuery를 사용한 AJAX 호출입니다. 간단한 jQuery AJAX 게시물은 다음과 같습니다.
$.post(url, values, function(data) {
// AJAX call completed, do something with returned data here
});
콜백 함수에서 결과를 처리하는 이유는 AJAX 호출이 반환되기를 기다리는 동안 현재 스레드를 차단하지 않기 때문입니다. 응답이 준비된 경우에만 콜백이 실행되어 현재 스레드가 그동안 다른 작업을 수행 할 수 있습니다.
이제 자바 스크립트가 await
키워드를 지원한다면 (물론 지원 하지 않는 ( 아직! )) 다음과 같이 동일한 결과를 얻을 수 있습니다.
var data = await $.post(url, values);
// AJAX call completed, do something with returned data here
훨씬 깔끔하지만 동기식 차단 코드를 도입 한 것 같습니다. 그러나 (가짜) JavaScript 컴파일러는 모든 것을 가져 와서 await
콜백에 연결 했으므로 런타임에 두 번째 예제는 첫 번째 예제와 똑같이 동작합니다.
많은 작업을 절약하는 것처럼 보이지 않을 수도 있지만 예외 처리 및 동기화 컨텍스트와 같은 경우 컴파일러가 실제로 많은 작업을 수행 합니다. 자세한 내용은 자주 묻는 질문 (FAQ) 과 Stephen Cleary의 블로그 시리즈를 추천합니다 .
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");
}
}
}