11

나는 네트워크 응용 프로그램을 작성하고 있습니다.이벤트 기반 비동기 패턴에서 작업 병렬 라이브러리 사용

메시지는 다음과 같은 전송을 통해 전송되는 :

Network.SendMessage (new FirstMessage()); 
이 메시지 유형, 도착과 같이 때 호출 할 이벤트 핸들러를 등록 할 수 있습니다

:

Network.RegisterMessageHandler<FirstMessage> (OnFirstMessageReceived); 

그리고 이벤트가 시작됩니다 :

public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs> e) 
{ 
} 

내 네트워크 응용 프로그램에 대한 사용자 지정 인증 절차를 쓰고 있습니다. 완료하려면 약 다섯 개의 메시지가 필요합니다. 작업 병렬 라이브러리를 사용하지 않고

, 정말처럼, 앞의 이벤트 처리기에서 각 절차의 다음 단계를 코딩하도록 강요 될 것이다 :

public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs> e) 
{ 
    Network.SendMessage(new SecondMessage()); 
} 

public void OnSecondMessageReceived(EventArgs<SecondMessageEventArgs> e) 
{ 
    Network.SendMessage(new ThirdMessage()); 
} 

public void OnThirdMessageReceived(EventArgs<ThirdMessageEventArgs> e) 
{ 
    Network.SendMessage(new FourthMessage()); 
} 

public void OnFourthMessageReceived(EventArgs<FourthMessageEventArgs> e) 
{ 
    // Authentication is complete 
} 

내가 주위에 점프의 아이디어를 좋아하지 않는다 이 부분과 그 일부를 코딩하는 소스 코드. 이해하고 편집하기가 어렵습니다.

작업 병렬 라이브러리가이 솔루션을 상당히 단순화한다고 들었습니다.

그러나 작업 병렬 라이브러리를 사용하여 읽은 많은 예제는 활성 작업 체인과 관련되어있었습니다.

public void Drink() {} 
public void Eat() {} 
public void Sleep() {} 

Task.Factory.StartNew( () => Drink()) 
      .ContinueWith(() => Eat() ) 
      .ContinueWith(() => Sleep()); 

이 각 이벤트 핸들러 메서드는 호출되는 내 이벤트 기반 비동기 패턴에서 반대 : 나는 '활성'가 무엇을 의미, 명시 적으로 호출 할 때 각 작업과 같이, 시작할 수 있다는 것입니다 메시지가 수신되면 즉

, 나는 이런 식으로 뭔가 할 수 없다 (을하지만 난 원하는) :

Task.Factory.StartNew( () => OnFirstMessageReceived() ) 
      .ContinueWith(() => OnSecondMessageReceived()) 
      .ContinueWith(() => OnThirdMessageReceived() ) 
      .ContinueWith(() => OnFourthMessageReceived()); 

나는 this article을 읽었습니다,하지만 난 확실히 그것을 이해하지 않습니다. 내가 필요한 것은 TaskCompletionSource과 관련이있는 것 같습니다. 위의 코드 블록과 같은 이벤트 기반 비동기 패턴에서 작업을 만들고 싶다면 어떻게 생겼을까요?

답변

20

당신은 TaskCompletionSource에 대해 옳았습니다. 그것은 EAP (이벤트 기반 비동기 패턴)를 TPL의 작업으로 변환하는 열쇠입니다.

여기에 설명되어 있습니다 : https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/tpl-and-traditional-async-programming#exposing-complex-eap-operations-as-tasks 여기

이 단순화 된 코드입니다, 당신이 할 필요가, 그 작업의 체인을 만들기 위해 지금

public static class Extensions 
{ 
    public static Task<XDocument> GetRssDownloadTask(
     this WebClient client, Uri rssFeedUri) 
    { 
     // task completion source is an object, which has some state. 
     // it gives out the task, which completes, when state turns "completed" 
     // or else it could be canceled or throw an exception 
     var tcs = new TaskCompletionSource<XDocument>(); 

     // now we subscribe to completed event. depending on event result 
     // we set TaskCompletionSource state completed, canceled, or error 
     client.DownloadStringCompleted += (sender, e) => 
     { 
        if(e.Cancelled) 
        { 
         tcs.SetCanceled(); 
        } 
        else if(null != e.Error) 
        { 
         tcs.SetException(e.Error); 
        } 
        else 
        { 
         tcs.SetResult(XDocument.Parse(e.Result)); 
        } 
     }; 

     // now we start asyncronous operation 
     client.DownloadStringAsync(rssFeedUri); 
     // and return the underlying task immediately 
     return tcs.Task; 
    } 
} 

, 당신의 연속성을을 (설정 그냥 어느 순간에 매우 충분하지 않습니다, 그리고 C# 5 await를하고 비동기은

그래서,이 코드는 다음과 같이 사용될 수) 그것으로 많이 도움이 될 것입니다

public static void Main() 
{ 
    var client = new WebClient(); 

    client.GetRssDownloadTask(
     new Uri("http://blogs.msdn.com/b/ericlippert/rss.aspx")) 
     .ContinueWith(t => { 
      ShowXmlInMyUI(t.Result); // show first result somewhere 
      // start a new task here if you want a chain sequence 
     }); 

    // or start it here if you want to get some rss feeds simultaneously 

    // if we had await now, we would add 
    // async keyword to Main method defenition and then 

    XDocument feedEric = await client.GetRssDownloadTask(
     new Uri("http://blogs.msdn.com/b/ericlippert/rss.aspx")); 
    XDocument feedJon = await client.GetRssDownloadTask(
     new Uri("http://feeds.feedburner.com/JonSkeetCodingBlog?format=xml")); 
    // it's chaining - one task starts executing after 
    // another, but it is still asynchronous 
} 
+0

이것은 좋은 팁이며, 실제로 WebClient와 함께 작업하는 것이 훨씬 쉬워졌습니다. 감사!! –

3

Jeremy Likness에는 블로그 항목 제목 Coroutines for Asynchronous Sequential Workflows using Reactive Extensions (Rx) (이)가 관심있어합니다. 그가 대답하려고하는 질문은 다음과 같습니다.

개념은 간단합니다. 순차적으로 수행 할 비동기 작업 세트를 원할 때가 있습니다. 서비스에서 목록을로드 한 다음 선택한 항목을로드 한 다음 애니메이션을 트리거해야합니다. 완료된 이벤트를 연결하거나 람다 식을 중첩하여 수행 할 수 있지만 더 깨끗한 방법이 있습니까?

+0

매우 흥미 롭습니다. 그것은 확실히 유용 할 수 있습니다. 나는 다른 답변이 무엇인지, 특히 Task Parallel Library를 사용하는 것들을 보게 될 것이다. – Jason

관련 문제