C#5.0의 비동기 함수 async\await

5259 단어
네트워크에서 데이터를 요청하거나 데이터베이스에 액세스하는 등 입출력 바인딩이 필요한 경우 비동기식 프로그래밍을 사용해야 합니다.또한 CPU 바인딩 코드(예를 들어 실행 비용이 비싼 계산)를 사용할 수 있어 비동기 코드를 작성하는 데 좋은 방안이다.C#는 비동기 코드를 쉽게 작성할 수 있는 언어 수준의 비동기 프로그래밍 모델을 가지고 있으며, 비동기 지원 라이브러리에 호출하거나 부합할 필요가 없다.작업 기반 비동기 모드(TAP)를 따릅니다.

비동기 모형의 기본 개술


입출력 바인딩 코드에 대해 await 한 동작을 하면 async 방법 중 하나 Task 또는 Task 로 되돌아옵니다.
CPU 바인딩 코드에 대해 await 동작을 하면 백엔드 스레드가 Task.Run 방법을 통해 시작됩니다.await 키는 실행 await 방법에 대한 호출자의 통제권을 정지하기 때문에 주목할 만한 부분이다.UI가 응답성이 있거나 서비스가 유연한 이유입니다.
입출력 바인딩 예: 웹 서비스에서 데이터 다운로드
private readonly HttpClient _httpClient = new HttpClient();

downloadButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI as the request
    // from the web service is happening.
    //
    // The UI thread is now free to perform other work.
    var stringData = await _httpClient.GetStringAsync(URL);
    DoSomethingWithData(stringData);
};


CPU 바인딩 예: 게임을 위해 계산을 실행하는 데 가장 좋은 해결 방법은 백엔드 스레드를 시작하는 것이다.Task를 사용한다.Run이 작업을 수행하고 await 결과를 가져옵니다.이렇게 하면 작업을 수행할 때 UI가 원활하게 실행됩니다.
private DamageResult CalculateDamageDone()
{
    // Code omitted:
    //
    // Does an expensive calculation and returns
    // the result of that calculation.
}


calculateButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI CalculateDamageDone()
    // performs its work.  The UI thread is free to perform other work.
    var damageResult = await Task.Run(() => CalculateDamageDone());
    DisplayDamage(damageResult);
};


내부 원리


비동기 조작은 많은 이동 부분과 관련된다.TaskTask의 내부 원리를 이해하려면 비동기를 깊이 있게 이해하는 것을 참고하십시오.
C#에서 컴파일러는 코드를 상태기로 변환하여 다음과 같은 내용을 추적합니다. await 도착했을 때 실행을 정지하고 백엔드 작업이 끝났을 때 계속 실행합니다.
이론적으로 말하자면 이것은 비동기적인 약속 모델의 실현이다.

요점 파악

  • 비동기 코드는 입출력 바인딩 및 CPU 바인딩 코드에 사용할 수 있지만 시나리오마다 다릅니다.
  • 비동기 코드 사용TaskTask은 백엔드에서 완성된 작업을 모델링하는 구조이다.
  • async 키워드는 방법을 비동기적인 방법으로 바꾸어 본문에서 await 키워드를 사용할 수 있도록 합니다.
  • await 키워드를 적용하면 호출 방법을 끊고 대기하는 작업이 끝날 때까지 제어권을 호출자에게 돌려줍니다.
  • 비동기식await만 사용할 수 있습니다.

  • CPU 바인딩 및 입출력 바인딩 작업 식별


    입출력 바인딩을 위해 작업하는 경우 asyncawait Task.Run 를 사용하십시오.작업 병렬 라이브러리를 사용할 수 없습니다.
    만약 당신이 CPU로 연결되어 있고 응답 능력을 중시한다면 asyncawait를 사용하고 다른 라인Task.Run에서 작업을 생성하십시오.만약 이 작업이 병행과 병행에 동시에 적용된다면, 작업 병행 라이브러리를 사용하는 것을 고려해야 한다.
    또한 코드의 실행을 시종 측정해야 한다.예를 들어, 다중 스레드 처리를 할 때, 상하문 전환 비용이 CPU 귀속 작업 비용보다 높을 수도 있다.모든 선택에는 절충이 있기 때문에 자신의 상황에 따라 정확한 절충 방안을 선택해야 한다.

    다중 작업 완료 대기 중


    여러 개의 데이터를 병렬로 검색해야 하는 상황에 처해 있음을 발견할 수 있다.Task API는 두 가지 방법(즉 Task.WhenAllTask.WhenAny을 포함한다. 이 방법들은 여러 백엔드 작업에서 기다리는 것을 막지 않는 비동기 코드를 작성할 수 있도록 한다.
    이 예제에서는 User 집합에 대한 userId 데이터 캡처 방법을 보여 줍니다.
    public async Task GetUser(int userId)
    {
        // Code omitted:
        //
        // Given a user Id {userId}, retrieves a User object corresponding
        // to the entry in the database with {userId} as its Id.
    }
    
    public static Task> GetUsers(IEnumerable userIds)
    {
        var getUserTasks = new List>();
    
        foreach (int userId in userIds)
        {
            getUserTasks.Add(GetUser(id));
        }
    
        return await Task.WhenAll(getUserTasks);
    }
    
    

    다음은 LINQ를 사용하여 보다 간결하게 작성할 수 있는 또 다른 방법입니다.
    public async Task GetUser(int userId)
    {
        // Code omitted:
        //
        // Given a user Id {userId}, retrieves a User object corresponding
        // to the entry in the database with {userId} as its Id.
    }
    
    public static async Task GetUsers(IEnumerable userIds)
    {
        var getUserTasks = userIds.Select(id => GetUser(id));
        return await Task.WhenAll(getUserTasks);
    }
    
    

    비록 그것의 코드는 비교적 적지만, LINQ와 비동기 코드를 혼합할 때 조심스럽게 조작해야 한다.LINQ가 지연된 실행을 사용하기 때문에 비동기 호출은 foreach() 순환에서처럼 즉시 발생하지 않습니다. 강제로 생성된 서열이 .ToList() 또는 .ToArray() 호출 순환을 통해 접근하지 않는 한.

    중요 정보 및 권장 사항

  • async 방법은 그 주체에 await 키워드가 있어야 한다. 그렇지 않으면 그들은 영원히 멈추지 않을 것이다!
  • Async를 작성한 모든 비동기식 방법의 명칭에 접미사로 추가해야 한다.
  • async void는 이벤트 처리 프로그램에만 사용해야 합니다.async void는 비동기 이벤트 처리 프로그램의 작업을 허용하는 유일한 방법이다. 이벤트가 되돌아오는 형식이 없기 때문이다TaskTask.다른 쌍async void은 TAP 모델을 따르지 않으며 다음과 같은 어려움이 있을 수 있습니다.
  • async void 방법에서 발생한 이상은 이 방법 외부에서 포획될 수 없다.
  • 테스트하기 매우 어렵다async void 방법.
  • 만약에 호출자가 async void 방법이 비동기적인 방법이라고 원하지 않는다면 이런 방법은 좋지 않은 부작용을 일으킬 수 있다.
  • LINQ 표현식에서 비동기적인 lambda를 사용할 때 LINQ의 Lambda 표현식이 실행을 지연시키는 것을 조심하십시오. 이것은 코드가 종료를 원하지 않을 때 실행을 중지할 수 있음을 의미합니다.만약 작성이 정확하지 않으면, 막힌 작업을 끌어들일 때, 자물쇠가 사라지기 쉽다.그 밖에 이런 비동기 코드 플러그인은 추정 코드의 집행에 더 많은 어려움을 가져올 수 있다.Async와 LINQ의 기능은 모두 매우 강하지만, 둘을 결합해서 사용할 때는 가능한 한 조심해야 한다.


  • 좋은 웹페이지 즐겨찾기