C에서 비동기식 복호화 및 대기 #

10398 단어 csharpasyncdotnet
작업할 때 이 두 키워드 asyncawait 를 여러 번 만날 수 있습니다.NET 프로젝트.이것은 매우 재미있는 일이지만, 이러한 코드를 처리할 때 백그라운드에서 무슨 일이 일어날지 이해하는 데도 도움이 된다.
도대체 무엇인지 깊이 이해하기 전에, 우리는 C에서 사용하는 임무와 라인에 대한 흔한 오해를 분명히 해야 한다.

🤔 작업 및 스레드


간단하게 말하면 임무는 라인이 아니다.다른 언어(예: JavaScript)에서 사용한 적이 있는 경우Promises 사용에 익숙해질 것입니다.임무는 본질적으로 약속입니다. 잠시 후에 완성할 것입니다. 비동기적인 조작이 되돌아오는 결과를 처리할 수 있습니다.이것은 임무가 이미 완성되었는지 확인하기 위해 고장 조회를 할 수 있다는 것을 의미한다.다른 한편, 라인은 운영체제급 코드가 실행하는 비교적 낮은 단계의 실현이다.
임무를 이해하는 것은 라인에 대한 추상이 매우 중요한 것이 아니다. 우리는 임무를 비동기적인 작업을 위한 추상으로 간주해야 한다.결론:
  • 작업이 스레드가 아님
  • 작업은 약속과 유사합니다. 비동기식 코드를 처리하기 위한 깨끗한 API를 제공하기로 약속합니다
  • 임무는 병행 수행을 보장할 수 없음
  • 작업을 통해 단독 라인에서 작업을 실행할 것을 명확하게 요청할 수 있다.API를 실행합니다.
  • TaskScheduler
  • 에서 작업 계획 실행

    🔮 '기다리기'키워드의 마력


    Stephen Cleary 그의 뛰어난 블로그 글에서 명확하게 언급한 바와 같이 async 키워드는wait만 사용합니다.따라서 비동기식 방법은 대기 키워드를 볼 때까지 다른 동기화 방법처럼 실행해야 한다.
    대기 키워드는 마법이 일어나는 곳이다.이것은 제어권을wait가 실행하는 방법의 호출자에게 되돌려주고, 최종적으로 IO 귀속 (예를 들어 웹 서비스 호출) 이나 CPU 귀속 작업 (예를 들어 CPU 밀집 계산) 에 응답할 수 있도록 합니다.async와await가 하는 모든 것은 우리에게 더 깨끗한 코드를 작성하기 위해 좋은 문법 설탕을 제공하는 것이다.
    다음 간단한 예제를 살펴보겠습니다.
    public async Task<string> DownloadString(string url)
    {
       var client = new HttpClient();
       var request = await client.GetAsync(url);
       var download = await request.Content.ReadAsStringAsync();
       return download;
    }
    
    동일한 코드는 엔진 덮개 아래에서 확장된 코드와 같습니다.
    public Task<String> DownloadString(string url) 
    { 
        var client = new HttpClient();
        var request = client.GetAsync(url); 
        var download = request.ContinueWith(http => 
            http.Result.Content.ReadAsStringAsync()); 
        return download.Unwrap(); 
    }
    
    보시다시피, 이것은 거의 일련의 수행해야 할 작업을 만들었고, TaskScheduler와 함께 줄을 서 있습니다.위의 코드는 괜찮지만, 항상 C가 제공하는 언어 구조를 사용하는 것도 유익하며, 모든 조작을 수동으로 실행할 필요가 없습니다!
    그 실행 순서는 다음과 같다.
  • 호출client.GetAsync(url)은 호출을 통해 낮은 단계에서 백그라운드에서 요청을 작성합니다.NET 라이브러리.
  • 기본 코드의 일부는 네트워크 API에서 운영체제에 작업을 의뢰할 때까지 동기화할 수 있습니다
  • 이때 작업을 만들고 비동기 코드의 원시 호출자에 거품을 일으켰다.이것은 여전히 미완성 임무이다!
  • 이 기간 동안 호출자는 작업의 상태를 조회할 수 있다
  • 네트워크 요청이 운영 체제 수준에서 완료되면 응답은 IO 완료 포트를 통해 되돌아오고 CLR은 CPU 중단을 통해 작업이 완료됐다는 알림을 받습니다
  • 응답 계획은 데이터를 확장하기 위해 다음 가용 스레드로 처리됩니다
  • 비동기식 방법의 나머지 부분은 계속 동기화
  • 이곳의 관건은 임무를 완성하기 위한 어떠한 전용 노선도 없다는 것이다.이것은 당신의 작업이 계속/완성되는 것을 의미하며, 그것을 시작하는 동일한 라인에서 실행될 수 없습니다.

    ☠️ async와await를 사용할 때의 흔한 문제

    asyncawait 을 사용하기 시작하면 코드의 모든 내용을 비동기화하려고 시도할 수 있습니다 (응, 해냈어요)😁). 그러나 코드에서는 함정을 피해야 한다.
  • 비동기식 비동기식 비동기식 비동기식 비동기화
  • 이것은 내가 async await로 두 손을 더럽힐 때 저지른 첫 번째 잘못이다!나는void 방법이 하나 있는데, 그 자체가 비동기적인 방법을 사용했다.호출 방법을 비동기화하지 않고wait를 사용할 수 없기 때문에, 호출 방법 async를void로 설정합니다!
    public async void GetResult() 
    {
        await SomeAsyncMethod();
    }
    
    문제는 GetResult 방법의 호출자가 SomeAsyncMethod() 결과에 대해 아무런 제어권이 없다는 것이다. 오류가 발생했을 때 디버그 호출 창고가 부족하고 이상이 발생했을 때 프로그램이 붕괴되는 등 다른 부작용을 초래할 수 있다.
    그러나 때로는 이런 상황을 피할 수 없다.저희 코드example에서 AsyncWpfApp을 열면 다음과 같은 코드가 표시됩니다.
    private async void AsyncParallelBtn_Click(object sender, RoutedEventArgs e)
    {
        ...
        var output = await RunAsyncParallelDemo.Start();
        ...
    }
    
    위와 같은 코드를 발견하면 WPF에서 이벤트 처리 프로그램의 서명을 변경할 수 없기 때문에 문제가 되지 않습니다.

    Nevertheless, it’s recommended to avoid using async void where possible.

  • "기다림"무시 또는 무시
  • 비동기적인 작업을 기다리는 것을 잊는 것은 매우 쉬운 오류입니다. 왜냐하면 컴파일러가 당신의 코드를 기꺼이 컴파일하기 때문에 불평하지 않기 때문입니다.다음 예시에서 우리는 비동기 함수만 호출할 수 있을 뿐 awaiting은 필요하지 않다.
    public void Caller()
    {
        Console.WriteLine("Before");
    
        // Deliberately forgetting to await
        DoSomeBackgroundWorkAsync();
    
        Console.WriteLine("After");
    }
    
    DoSomeBackgroundWorkAsync() 방법은 호출자 방법에 임무(임무 또는 임무, 실현에 달려 있음)를 되돌려 주고 실제로 수행하지 않습니다.

    Therefore, be mindful when you are dealing with async methods (especially with third party libraries) not to forget to use await

  • 비동기식 작업을 막습니다.결과와Wait()
  • 이것은 개발자가 (자신도 모르게) 뛰어드는 또 다른 흔한 함정이다😋) 동기화 방법에서 비동기 코드를 실행해야 할 때다음 예제를 살펴보겠습니다.
    public void DoSomeWork()
    {
        var result = DoAsyncWork().Result;
    }
    
    언뜻 보기에는 .Result 속성을 사용하는 것이 매우 편리할 수 있다.그러나 이것은 심각한 결과를 초래할 수 있다deadlock problems.이런 상황을 피하기 위해서는 일반적으로 호출자의 방법을 비동기화해야 한다.이것은 변경 사항에 등급 연결 효과가 발생하기 때문에 많은 작업을 해야 할 수도 있습니다.그러나 이것은 통상적으로 더욱 취할 만하다.
    SDN에 명시된 것처럼 비차단 코드를 작성하는 방법은 다음과 같습니다.

    It’s recommended to make the caller async where you would end up making a lot of cascading changes to your codebase although it could be painful if you are working on a legacy project.


    결론


    나는 네가 내가 이 글을 쓴 것처럼 그것을 좋아하길 바란다.밑줄은 임무가 거의 항상 가장 좋은 선택이라는 것이다.운영 체제의 스레드가 낭비되지 않도록 더욱 강력한 API를 제공합니다.
    준비됐어요?Github repo에 액세스하여 예제 코드를 확인하십시오.
    https://github.com/sahan91/c-sharp-tasks

    제안 또는 오류 발견?


    만약 당신이 내가 설명한 어떤 일에 오해가 있다고 생각한다면 아래에서 마음대로 평론해 주십시오.) 또한 오류를 발견하거나 건의가 있으면 나의 Github repo에서 요청을 열어 주십시오.건배!

    공구서류

  • https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl
  • https://blog.stephencleary.com/2012/02/async-and-await.html
  • https://markheath.net/post/async-antipatterns
  • https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
  • 좋은 웹페이지 즐겨찾기