ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • async, await에 대한 설명
    @ 17. 1 ~ 18/C# 멀티스레드 2017. 8. 19. 13:22

    출처 : http://blog.stephencleary.com/2012/02/async-and-await.html


    키워드 소개

    비동기 메서드는 다음과 같다.

    public async Task DoSomethingAsync()
    {
      // In the Real World, we would actually do something...
      // For this example, we're just going to (asynchronously) wait 100ms.
      await Task.Delay(100);
    }

    async키워드는 해당 메소드에서 await키워드를 사용가능하게 메소드 결과 처리 방법을 변경한다.

    비동기 메소드의 시작은 다른 메소드와 마찬가지로 실행된다. 즉 , await이 될떄까지 동기적으로 실행한다.

    await 키워드는 상황이 비동기 적으로 발생할 수 있는 곳이다. 

    대기 상태가 이미 완료된 경우 메서드는 계속 실행된다. 일반적인 메서드와 마찬가지로 동기적으로 실행한다.

    대기가 완료되지 않았음을 확인하면 비동기적으로 작동한다. 이 메소드는 완료될때 메소드의 나머지 부분을 실행하기를 기다리고 있으며 비동기 메소드에서 리턴한다.

    나중에 대기가 완료되면 나머지 비동기 메소드가 실행된다. 대기열에 내장된 대기열을 기다리고 있다면 나머지 비동기 메소드는 대기중 반환되지 전에 캡처 된 컨텍스트에서 실행된다.


     Awaitables

    닷넷 프레임워크에서는 Task<T>와 Task라는 두가지 유형이 있다.

    public async Task NewStuffAsync()
    {
      // Use await and have fun with the new stuff.
      await ...
    }
    
    public Task MyOldTaskParallelLibraryCode()
    {
      // Note that this is not an async method, so we can't use await in here.
      ...
    }
    
    public async Task ComposeAsync()
    {
      // We can await Tasks, regardless of where they come from.
      await NewStuffAsync();
      await MyOldTaskParallelLibraryCode();
    }

    매우 간단한 비동기 메소드가 있는 경우 await 키워드를 사용하지 않고 (Task.FromResult를 사용하여) 작성할 수 있습니다. 기다리지 않고 작성할 수 있으면 기다리지 않고 작성하고 메소드에서 async 키워드를 제거해야한다. Task.FromResult를 반환하는 비동기 메소드는 값을 반환하는 async메소드보다 효율적이다.


    return type

    비동기 메소드는 Task<T>, Task, Void를 반환할 수 있다. 거의 모든 경우에는 Task<T>, Task로 반환하고 정말 필요할때만 void를 반환한다.

    Task<T>, Task를 반환하는 비동기 메서드가 있으면 결과를 기다릴 수 있다. void메소드를 사용하면 기다릴 것도 없다(기다릴 수 없다. 억지로 ㅇ기다릴 순 있음..)

    그리고 가능하면 void 반환은 사용하지 말것.

    최상위 유형의 작업에는 void 를 사용할 수 있음.


    Context

    컨텍스트란 무엇인가?

    간단하게

    1. UI스레드를 사용중이라면 UI 컨텍스트이다.

    2. ASP.NET 요청에 응답하는 경우 ASP.NET요청 컨텍스트 입니다.

    3. 그렇지 않으면 대게 스레드 풀 컨텍스트 입니다.


    좀더 복잡하게

    1. SynchronizationContext.Curret가 null이 아닌 경우 현재 SynchronizationContext입니다. UI 및 ASP.NET 요청 컨텍스트는 SynchronizationContext.컨텍스트 입니다.

    2. 그렇지 않으면 현재 TaskScheduler입니다. (TaskScheduler.Default는 스레드 풀 컨텍스트 임)


    현실세계에서는 무엇을 의미하는가? 한가지 UI/ASP.NET 컨텍스트 캡처 및 복원은 명백하게 수행된다.


    Avoiding Context

    대부분의 경우 매인 컨텍스로 다시 동기화할 필요가 없다.

    대부분의 비동기 메소드는 다음과 같은 사항을 고려하여 설계된다.

    그들은 다른 연산을 기다리고 있으며 각각은 비동기 연산 자체를 표현한다.

    이경우 호출자에게 호출하여 현재 컨텍스트를 캡처하지 않도록 말하고자 합니다.

    ConfigureAwait and passing false, e.g.:

    private async Task DownloadFileAsync(string fileName)
    {
      // Use HttpClient or whatever to download the file contents.
      var fileContents = await DownloadFileContentsAsync(fileName).ConfigureAwait(false);
    
      // Note that because of the ConfigureAwait(false), we are not on the original context here.
      // Instead, we're running on the thread pool.
    
      // Write the file contents out to a disk file.
      await WriteToDiskAsync(fileName, fileContents).ConfigureAwait(false);
    
      // The second call to ConfigureAwait(false) is not *required*, but it is Good Practice.
    }
    
    // WinForms example (it works exactly the same for WPF).
    private async void DownloadFileButton_Click(object sender, EventArgs e)
    {
      // Since we asynchronously wait, the UI thread is not blocked by the file download.
      await DownloadFileAsync(fileNameTextBox.Text);
    
      // Since we resume on the UI context, we can directly access UI elements.
      resultTextBox.Text = "File downloaded!";
    }

    이 예제에서 중요한 점은 비동기 메서드 호출의 각 수준에는 자체 컨텍스트가 있다는 점이다.

    DownloadFileButton_Click은 UI컨텍스트에서 시작되어 DownloadFileAsync가 호출되었습니다.

    DownloadFileAsync의 시작은 UI컨텍스트에서 시작되었지만 내부에서는

    ConfigureAwait(false)를 호출하여 UI 컨텍스트를 벗어났다(스레드 풀에서 실행된다.)

    DownloadFileAsync가 완료되고 DownloadFileButton_Click이 다시 시작되면 UI 컨텍스트에서 다시 시작된다.

    컨텍스트가 필요하다는 것을 알지 못한다면 COnfigureAwait(false)를 사용하는것이 어림직작으로 좋은 규칙이다.


    Async Composition

    지금까지는 직렬 구성만 고려했다.

    비동기 메서드는 한번에 하나의 작업만 대기한다.

    여러 작업을 시작하여 그 중 하나가(또는 모두) 완료 될때까지 기다릴 수 있다.

    작업을 시작하고 나중에까지 기다리지 않고 이 작업을 수행할 수 있습니다.


    public async Task DoOperationsConcurrentlyAsync()
    {
      Task[] tasks = new Task[3];
      tasks[0] = DoOperation0Async();
      tasks[1] = DoOperation1Async();
      tasks[2] = DoOperation2Async();
    
      // At this point, all three tasks are running at the same time.
    
      // Now, we await them all.
      await Task.WhenAll(tasks);
    }
    
    public async Task<int> GetFirstToRespondAsync()
    {
      // Call two web services; take the first response.
      Task<int>[] tasks = new[] { WebService1Async(), WebService2Async() };
    
      // Await for the first one to respond.
      Task<int> firstTask = await Task.WhenAny(tasks);
    
      // Return the result.
      return await firstTask;
    }

    동시 구성(Task.WhenAll 또는 Task.WhenAny)을 사용하여 간단한 동시 작업을 수행 할 수 있습니다.

    Task.Run과 함께 이 메소드를 사용하여 간단한 병렬 계산을 수행할 수도 있다.

    그러나 이것은 Task Parallel Libraty의 대체물이 아니다. 


    Guidelines

    Read the Task-based Asynchronous Pattern (TAP) document. It is extremely well-written, and includes guidance on API design and the proper use of async/await (including cancellation and progress reporting).

    There are many new await-friendly techniques that should be used instead of the old blocking techniques. If you have any of these Old examples in your new async code, you’re Doing It Wrong(TM):

    OldNewDescription
    task.Waitawait taskWait/await for a task to complete
    task.Resultawait taskGet the result of a completed task
    Task.WaitAnyawait Task.WhenAnyWait/await for one of a collection of tasks to complete
    Task.WaitAllawait Task.WhenAllWait/await for every one of a collection of tasks to complete
    Thread.Sleepawait Task.DelayWait/await for a period of time
    Task constructorTask.Run or TaskFactory.StartNewCreate a code-based task

    Next Steps

    I have published an MSDN article Best Practices in Asynchronous Programming, which further explains the “avoid async void”, “async all the way” and “configure context” guidelines.

    The official MSDN documentation is quite good; they include an online version of the Task-based Asynchronous Pattern document which is excellent, covering the designs of asynchronous methods.

    The async team has published an async/await FAQ that is a great place to continue learning about async. They have pointers to the best blog posts and videos on there. Also, pretty much any blog post by Stephen Toub is instructive!

    Of course, another resource is my own blog.

    '@ 17. 1 ~ 18 > C# 멀티스레드' 카테고리의 다른 글

    읽기 / 쓰기 락  (0) 2018.06.27
    스레드 로컬 저장소  (0) 2018.06.21
    스레드 동기화란?  (0) 2018.03.05
    동시성 컬렉션 사용  (0) 2017.08.20
    데드락 걸리는 async 코드  (0) 2017.08.19
Designed by Tistory.