ProgramingTip

"이전 내장 대리자"를 종료 실행 중단

bestdevel 2020. 12. 10. 20:55
반응형

"이전 내장 대리자"를 종료 실행 중단


나는 더 단순함을 바라면서 이전의 fire-and-forget 호출을 새로운 구문으로 바꾸려고 노력하고 있는데 그것은 나를 피하는 것입니다. 여기에 예가 있습니다.

class Program
{
    static void DoIt(string entry) 
    { 
        Console.WriteLine("Message: " + entry);
    }

    static async void DoIt2(string entry)
    {
        await Task.Yield();
        Console.WriteLine("Message2: " + entry);
    }

    static void Main(string[] args)
    {
        // old way
        Action<string> async = DoIt;
        async.BeginInvoke("Test", ar => { async.EndInvoke(ar); ar.AsyncWaitHandle.Close(); }, null);
        Console.WriteLine("old-way main thread invoker finished");
        // new way
        DoIt2("Test2");   
        Console.WriteLine("new-way main thread invoker finished");
        Console.ReadLine();
    }
}

두 접근 방식 모두 동일한 작업을 수행하지만 내가 얻은 것 ( EndInvoke핸들을 닫을 필요 가없고 아직 논란의 여지가 있음)을 기다려야하는 새로운 방식으로 잃고 있습니다. Task.Yield()실제로 새로운 문제를 제기합니다. 한 줄을 추가하기 위해 기존의 모든 것이 F & F 메소드를 다시 작성해야합니다. 성능 / 정리에서 보이지 않는 이점이 있습니까?

백그라운드 방법을 사용할 수없는 경우 어떻게 적용 할 수 있습니까? 확고한 방법이없는 것입니다. Task.Run ()을 기다리고 래퍼를 사용하는 방법?

편집 : 이제 실제 질문이 누락되어 있습니다. 질문은 다음과 가변합니다. 동기 방식 A ()가 주어지면 "이전 방식"보다 더 복잡한 솔루션을 얻지 않고 화재 및 잊어 버리기 방식으로 async/ await사용하여 호출 할 수있는 방법이 있습니다.


피하십시오 async void. 오류 처리에 대해 까다로운 의미가 있습니다. 나는 어떤 사람들이 그것을 "불과 잊는다"라고 부르는 것을 알고 싶습니다 나는 보통 "불과 충돌"이라는 표현을 사용합니다.

질문은 다음과 가변합니다. 동기 메서드 A ()가 주어지면 "이전 방식"보다 더 복잡한 솔루션을 얻지 않고 그대로 / 대기 방식을 사용하여 표현식으로 호출 할 수있는 방법

async/ 는 필요하지 않습니다 await. 다음과 같이 호출하십시오.

Task.Run(A);

다른 답변 과이 훌륭한 블로그 게시물 에서 언급했듯이 async voidUI 이벤트 처리기 외부에서 사용하는 것을 피하고 싶습니다 . 당신이 원하는 경우 안전 "화재와 잊지" async방법이 패턴을 사용하는 것을 고려 (@ReedCopsey에 신용을,이 방법은 그가 채팅 대화 나에게 준 하나입니다) :

  1. 에 대한 확장 메서드를 만듭니다 Task. 전달 된 것을 실행하고 Task모든 예외를 실행합니다.

    static async void FireAndForget(this Task task)
    {
       try
       {
            await task;
       }
       catch (Exception e)
       {
           // log errors
       }
    }
    
  2. Task스타일 async메서드를 만들 때 항상 사용하십시오 async void.

  3. 다음과 같은 방법으로 메소드를 호출하십시오.

    MyTaskAsyncMethod().FireAndForget();
    

필요하지 않습니다 await( await경고를 생성하지도 않습니다 ). 또한 모든 오류를 올바르게 처리 할 수 ​​있으며 여기가 유일한 위치 async void이므로 try/catch모든 곳에 블록 을 두는 것을 기억할 필요가 없습니다 .

이것은 또한 당신이 실제로 그것을 일반적으로 원할 경우 "실행 후 잊어 버리기"방법으로 방법을 사용 하지 않는 옵션을 제공합니다 .asyncawait


나에게 어떤 것을 "기다리기"와 "불만 잊고"는 두 가지 직교 개념 인 것 같다. 메서드를 비동기 적으로 시작하고 결과를 신경 쓰지 않거나 작업이 완료된 후 원래 컨텍스트에서 실행을 재개하려고합니다 (그리고 반환 값을 사용할 수 있음). 이것이 바로 await가하는 일입니다. ThreadPool 스레드에서 메서드를 실행하고 싶다면 (UI가 차단되지 않도록)

Task.Factory.StartNew(() => DoIt2("Test2"))

그리고 당신은 괜찮을 것입니다.


제 생각에는 이러한 '실행 후 잊어 버리기'방법이 일련의 순차적 명령으로 논리를 작성할 수 있도록 UI와 백그라운드 코드를 인터리브하는 깔끔한 방법이 필요한 인공물이라는 것입니다. async / await는 SynchronizationContext를 통해 마샬링을 처리하므로 문제가되지 않습니다. 더 긴 시퀀스의 인라인 코드는 이전에 백그라운드 스레드의 루틴에서 시작되었던 '실행 후 잊어 버리기'블록이됩니다. 그것은 사실상 패턴의 반전입니다.

주요 차이점은 await 사이의 블록이 BeginInvoke보다 Invoke와 더 유사하다는 것입니다. BeginInvoke와 같은 동작이 더 필요한 경우 다음 비동기 메서드 (Task 반환)를 호출 한 다음 'BeginInvoke'하려는 코드가 나올 때까지 실제로 반환 된 Task를 기다리지 마십시오.

    public async void Method()
    {
        //Do UI stuff
        await SomeTaskAsync();
        //Do more UI stuff (as if called via Invoke from a thread)
        var nextTask = NextTaskAsync();
        //Do UI stuff while task is running (as if called via BeginInvoke from a thread)
        await nextTask;
    }

참고 URL : https://stackoverflow.com/questions/12803012/fire-and-forget-with-async-vs-old-async-delegate

반응형