Infinite Task 구현과 값 가져오기

Socket client 인스턴스를 여러개 사용할때.. - 9H05T 님의 게시물 #9

이전의 답변 중에 1:1 통신에서 1:N 통신으로 바꾸게 되면서 Device의 스케쥴링을 처리하라고 답변을 드렸었는데 다시 구현해볼려고 하니 어렵네요.

제가 생각한 것은 1:1을 Task를 이용하여 N개로 나누기입니다.
중간에 통신이 끊기지 않고 진행된다는 가정하에 지속적으로 값을 업데이트 하려고 합니다.

이 과정에서 Task에 infinite loop가 들어가는데 이 값을 binding 하여 UI에 값을 업데이트 하려고 한다면 어떻게 해야 할까요?

제가 짜본 코드 입니다.

async void FooAsync()
{
    CancellationTokenSource source = new CancellationTokenSource();
    var token = source.Token;
    var result = await Task.Run(() => DoWork(token), token);

    token.ThrowIfCancellationRequested(); // <-여기서 부터 실행되지 않음

    foreach (var item in result)
    {
        Console.WriteLine(item.ToString());
    }
}

IEnumerable<TResult> DoWork(CancellationToken token)
{
    while(!token.IsCancellationRequested) 
    { 
        /* Do something */
       yield return result; 
    }
}

여기서 문제는 FooAsync result가 문제인데요. Task가 infinite다 보니 result에서 무한 대기상태에 걸립니다.

어디가 잘못 된 것일까요? 접근방법이 문제가 될 수도 있다는 생각이 듭니다.

3개의 좋아요

다양한 처리 방식이 있겠습니다만 IAsyncEnumerable를 사용해서 작성하신 코드를 최대한 유지할 수 있습니다.

using System.Runtime.CompilerServices;


var cts = new CancellationTokenSource();
var count = 0;
await foreach (var plcResult in ListenPLCEnumerator(cts.Token))
{
    Console.WriteLine($"{plcResult} PLC 수신");

    // 10개만 처리하고 종료
    count++;
    if (count == 10)
        cts.Cancel();
}

static async IAsyncEnumerable<PLCResult> ListenPLCEnumerator([EnumeratorCancellation] CancellationToken ct)
{
    while (ct.IsCancellationRequested is false)
    {
        var number = Random.Shared.Next(100, 500);
        await Task.Delay(number);
        yield return new PLCResult(number);
    }
}

record PLCResult(int number);

비동기 스트림을 사용해서 ListenPLCEnumerator에서 PLC의 값을 수신했을 때 그것을 await foreach문을 통해 처리할 수 있게 됩니다.

(예시 코드에서는 처리시간 및 PLC 정보를 임의의 난수로 처리하여 시뮬레이션 했습니다)

| 결과

PLCResult { number = 164 } PLC 수신
PLCResult { number = 228 } PLC 수신
PLCResult { number = 266 } PLC 수신
PLCResult { number = 494 } PLC 수신
PLCResult { number = 309 } PLC 수신
PLCResult { number = 131 } PLC 수신
PLCResult { number = 193 } PLC 수신
PLCResult { number = 187 } PLC 수신
PLCResult { number = 192 } PLC 수신
PLCResult { number = 287 } PLC 수신
6개의 좋아요

올려주신 코드를 가지고 Task로 결과를 받아오고
그 결과를 WPF UI에 바인딩처리해서 표시 하는 간단한 예제를 작성해 보았습니다.

code_check/QnA/WPF/InfiniteTask at main · tyeom/code_check (github.com)


foreach (var item in result)

부분에서 대기 부분에 의해 해당 딜레이 만큼 UI행이 걸리면서 자연스럽지 못하고 있는데

C# 8.0 을 사용할 수 있는 환경이시라면 @dimohy 님 제안처럼 비동기스트림으로 처리하시면 되고 ( IAsyncEnumerable)
또는 별도 스레드 처리하셔도 될 것 같습니다.

33

7개의 좋아요

github에 질답용 repo가 따로 있으시다니… :+1: 따봉입니다.

4개의 좋아요