새로운 C # await 기능은 무엇을합니까? [닫은]


83

누구든지이 await기능이 무엇을하는지 설명 할 수 있습니까 ?




dotnetperls.com/async 에도 좋은 예가 있습니다 .
Miljen Mikic 2015

이 질문이 너무 광범위하거나 닫혀 야한다고 생각하지 않습니다. 하나의 키워드가 무엇을 의미하는지 묻습니다. (이전 버전이 어떻게
달라졌

답변:


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


20
완성도를 위해 위의 코드는 async 키워드로 장식 된 메서드로 래핑되어야한다고 추가하겠습니다. 이 메서드는 첫 번째 await 키워드가 발견 되 자마자 즉시 반환됩니다.
Przemek

14
즉, 메서드를 "일시 중지"할 수 있지만 스레드를 일시 중지하거나 차단하지 않는다는 점에 유의해야합니다.
Matt Crinklaw-Vogt

47

기본적으로 asyncawait키워드를 사용하면 메서드 실행이의 모든 사용에서 중지되도록 지정하여 await비동기 메서드 호출을 표시 한 다음 비동기 작업이 완료되면 다시 시작 하도록 지정할 수 있습니다 . 이를 통해 앱의 기본 스레드에서 메서드를 호출하고 스레드 및 조인을 명시 적으로 정의하거나 앱의 기본 스레드를 차단할 필요없이 복잡한 작업을 비동기 적으로 처리 할 수 ​​있습니다.

yield returnIEnumerable을 생성하는 메서드 의 문과 다소 유사하다고 생각하십시오 . 런타임이에 도달 yield하면 기본적으로 메서드의 현재 상태를 저장하고 산출되는 값 또는 참조를 반환합니다. 다음에 IEnumerator.MoveNext ()가 반환 객체 (런타임에 의해 내부적으로 생성됨)에서 호출되면 메서드의 이전 상태가 스택에 복원되고 다음 줄에서 실행이 계속됩니다 yield return. 방법. 이 키워드가 없으면 IEnumerator 유형은 상태를 저장하고 반복 요청을 처리하기 위해 사용자 정의해야합니다. 메서드는 실제로 매우 복잡해질 수 있습니다.

마찬가지로,로 표시하는 방법은 async적어도 하나 있어야 await. 온 await, 현재의 thread의 상태와 호출 스택을 절약 할 수 런타임은, 비동기 호출, 다음 메시지를 처리하고 응답 응용 프로그램을 유지하는 런타임의 메시지 루프에 풀림 등을 확인합니다. 비동기 작업이 완료되면 다음 예약 기회에 비동기 작업을위한 호출 스택이 다시 푸시되어 호출이 동기식 인 것처럼 계속됩니다.

따라서이 두 가지 새로운 키워드는 기본적으로 yield return사용자 지정 열거 형 생성을 단순화 한 것처럼 비동기 프로세스의 코딩을 단순화합니다. 몇 가지 키워드와 약간의 배경 지식 만 있으면 기존 비동기 패턴의 혼란스럽고 종종 오류가 발생하기 쉬운 세부 정보를 모두 건너 뛸 수 있습니다. 이는 Silverlight의 WPF 인 Winforms와 같은 거의 모든 이벤트 기반 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
작업 상태 : WaitingForActivation
ENTER
비동기 작업 반복 1
비동기 작업 반복 2
비동기 작업 반복 3
비동기 작업 반복 4
비동기 작업 반복 5
비동기 작업 반복 6
비동기 작업 반복 7
비동기 작업 반복 8
비동기 작업 반복 9
종료 일해()


1
또한 할 수있는 작업을 제공하기 전에 3 초 동안 발신자를 차단한다는 것을 알고 await있습니까? 이것이 UI 스레드에서 호출되면 3 초 동안 UI 스레드를 차단한다는 의미입니까? 이 모델의 아이디어는 그런 일을 피하는 것입니다.
Servy

1
@Servy 예, 그게 요점이었습니다. 실행의 모든 ​​단계를 보여줍니다. 이것은 실제 사례가 아닙니다.
Anri 2013

7
@Servy 당신은 나를 트롤링?
Anri 2013

2
아니. 나는 당신이 당신의 대답을 향상시킬 수 있도록 노력하고 있습니다.
Servy 2013

2
@ Anri ... 여기에서 노력 해주셔서 감사합니다. 감사합니다 !!
Praveen Prajapati 2013-08-21

11

.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의 블로그 시리즈를 추천합니다 .


이 가짜 비유를 고수하면서 (나에게 큰 도움이 되었으니 감사합니다!) "이후 모든 것"이란 무엇을 의미합니까? 동일한 기능 (메소드)의 범위 내에있는 모든 것? 아니면 그 이후의 모든 것이 호출 스택에 추가 될 수있는 모든 것입니까?

2
"Everything after"= 나머지 메소드. 컴파일러는 메서드의 나머지 부분을 콜백으로 효과적으로 다시 작성하고 제어는 현재 메서드의 호출자에게 즉시 반환됩니다.
Todd Menier

1
Brilliant Todd, 설명해 주셔서 다시 한 번 감사드립니다. 다른 사람들에게도 유용합니다.

-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.