programing

작업 완료 시기소스를 사용하시겠습니까?

sourcejob 2023. 5. 9. 22:37
반응형

작업 완료 시기소스를 사용하시겠습니까?

AFAIK, 그것이 아는 것은 어느 순간, 그것이SetResult또는SetException하여 메드를완료니다합Task<T>그것을 통해 드러난.Task소유물.

다시 말해서, 그것은 생산자 역할을 합니다.Task<TResult>그리고 그것의 완성.

여기서 예를 보았습니다.

▁▁way▁▁a▁i▁if한요▁need를 실행하는 방법이 필요한 경우.Func<T>으로 '으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으으Task<T>그 작업을 나타내는 것입니다.

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException(“function”); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        {  
            T result = function(); 
            tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}

만약 내가 가지고 있지 않았다면 사용할 수 있었을 것입니다.Task.Factory.StartNew하지만 나는 가지고 있습니다.Task.Factory.StartNew.

질문:.

누군가 직접적으로 관련된 시나리오를 예로 들어 설명해 주시겠습니까?TaskCompletionSource그리고 내가 가지고 있지 않은 가상의 상황에 대해서도.Task.Factory.StartNew?

이벤트 기반 API만 사용할 수 있을 때 주로 사용합니다(예: Windows Phone 8 소켓).

public Task<Args> SomeApiWrapper()
{
    TaskCompletionSource<Args> tcs = new TaskCompletionSource<Args>(); 

    var obj = new SomeApi();

    // will get raised, when the work is done
    obj.Done += (args) => 
    {
        // this will notify the caller 
        // of the SomeApiWrapper that 
        // the task just completed
        tcs.SetResult(args);
    }

    // start the work
    obj.Do();

    return tcs.Task;
}

따라서 C#5와 함께 사용할 경우 특히 유용합니다.async키워드

경험으로는, 내경으는로험,는로,TaskCompletionSource의 오래비패현턴포로데좋장다습니는하으대적을동기된▁로 포장하는 데 좋습니다.async/await양식.

제가 생각할 수 있는 가장 유익한 예는 함께 일할 때입니다.Socket패턴은 APM EAP 패턴은 .awaitable Task 하는 TcpListener그리고.TcpClient갖고 있다.

저는 개인적으로 몇 가지 문제가 있습니다.NetworkStream계급적이고 원시적인 것을 선호합니다.Socket나 또한 사랑하기 때문에.async/await 을 만들었습니다.SocketExtender여러 확장 메서드를 생성합니다.Socket.

이 모든 방법은 다음을 사용합니다.TaskCompletionSource<T>다음과 같이 비동기 호출을 처리합니다.

    public static Task<Socket> AcceptAsync(this Socket socket)
    {
        if (socket == null)
            throw new ArgumentNullException("socket");

        var tcs = new TaskCompletionSource<Socket>();

        socket.BeginAccept(asyncResult =>
        {
            try
            {
                var s = asyncResult.AsyncState as Socket;
                var client = s.EndAccept(asyncResult);

                tcs.SetResult(client);
            }
            catch (Exception ex)
            {
                tcs.SetException(ex);
            }

        }, socket);

        return tcs.Task;
    }

는 는나통과를 합니다.socketBeginAccept로컬 매개 변수를 올릴 필요 없이 컴파일러의 성능을 약간 향상시킬 수 있는 방법입니다.

그렇다면 그 모든 것의 아름다움은:

 var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 listener.Bind(new IPEndPoint(IPAddress.Loopback, 2610));
 listener.Listen(10);

 var client = await listener.AcceptAsync();

고전적인 ▁for.TaskCompletionSource내 방법이 반드시 시간이 많이 걸리는 작업을 수행하지 않아도 될 가능성이 있습니다.새로운 스레드를 사용할 특정 사례를 선택할 수 있습니다.

이에 대한 좋은 예는 캐시를 사용하는 경우입니다.당신은 가질 수 있습니다.GetResourceAsync요청된 리소스를 캐시에서 찾고 한 번에 반환하는 메소드(새 스레드를 사용하지 않고 사용)TaskCompletionSource리소스가 발견된 경우.되지 않은 에만 새 Task.Run().

코드 예제는 다음과 같습니다.태스크를 사용하여 조건부로 비동기식으로 코드를 실행하는 방법

블로그 게시물에서, Levi Botelho는 어떻게 사용하는지 설명합니다.TaskCompletionSource프로세스를 시작하고 종료를 기다릴 수 있도록 프로세스에 대한 비동기 래퍼를 작성합니다.

public static Task RunProcessAsync(string processPath)
{
    var tcs = new TaskCompletionSource<object>();
    var process = new Process
    {
        EnableRaisingEvents = true,
        StartInfo = new ProcessStartInfo(processPath)
        {
            RedirectStandardError = true,
            UseShellExecute = false
        }
    };
    process.Exited += (sender, args) =>
    {
        if (process.ExitCode != 0)
        {
            var errorMessage = process.StandardError.ReadToEnd();
            tcs.SetException(new InvalidOperationException("The process did not exit correctly. " +
                "The corresponding error message was: " + errorMessage));
        }
        else
        {
            tcs.SetResult(null);
        }
        process.Dispose();
    };
    process.Start();
    return tcs.Task;
}

및 그 용법.

await RunProcessAsync("myexecutable.exe");

아무도 언급하지 않은 것처럼 보이지만 유닛 테스트도 충분히 실생활로 간주할 수 있을 것 같습니다.

찾았습니다TaskCompletionSource비동기 방법으로 종속성을 조롱할 때 유용합니다.

테스트 중인 실제 프로그램:

public interface IEntityFacade
{
  Task<Entity> GetByIdAsync(string id);
}

단위 검정:

// set up mock dependency (here with NSubstitute)

TaskCompletionSource<Entity> queryTaskDriver = new TaskCompletionSource<Entity>();

IEntityFacade entityFacade = Substitute.For<IEntityFacade>();

entityFacade.GetByIdAsync(Arg.Any<string>()).Returns(queryTaskDriver.Task);

// later on, in the "Act" phase

private void When_Task_Completes_Successfully()
{
  queryTaskDriver.SetResult(someExpectedEntity);
  // ...
}

private void When_Task_Gives_Error()
{
  queryTaskDriver.SetException(someExpectedException);
  // ...
}

결국, 태스크 완료의 이러한 사용소스는 "코드를 실행하지 않는 작업 개체"의 또 다른 사례로 보입니다.

작업 완료소스는 코드를 실행하지 않는 작업 개체를 만드는 데 사용됩니다.실제 시나리오에서는 작업 완료소스는 I/O 바인딩 작업에 이상적입니다.이렇게 하면 작업 기간 동안 스레드를 차단하지 않고도 작업의 모든 이점(예: 반환 값, 계속 등)을 얻을 수 있습니다."함수"가 I/O 바인딩 작업인 경우 새 작업을 사용하여 스레드를 차단하지 않는 것이 좋습니다.대신 작업 완료 사용소스, I/O 바인딩 작업이 완료되거나 장애가 발생할 때만 나타내는 슬레이브 작업을 생성할 수 있습니다.

게시물에는 "Parallel Programming with."의 적절한 설명과 함께 실제 사례가 있습니다.NET" 블로그.꼭 읽어보셔야겠지만, 어쨌든 여기 요약이 있습니다.

블로그 게시물에는 다음을 위한 두 가지 구현이 나와 있습니다.

"사용자가 제공한 시간 초과가 발생할 때까지 실제로 예약되지 않는 "임시" 작업을 만드는 공장 방식입니다."

표시된 첫 번째 구현은 다음을 기반으로 합니다.Task<>그리고 두 가지 큰 결점이 있습니다.두 번째 구현 게시물은 다음을 사용하여 이러한 문제를 완화합니다.TaskCompletionSource<>.

두 번째 구현은 다음과 같습니다.

public static Task StartNewDelayed(int millisecondsDelay, Action action)
{
    // Validate arguments
    if (millisecondsDelay < 0)
        throw new ArgumentOutOfRangeException("millisecondsDelay");
    if (action == null) throw new ArgumentNullException("action");

    // Create a trigger used to start the task
    var tcs = new TaskCompletionSource<object>();

    // Start a timer that will trigger it
    var timer = new Timer(
        _ => tcs.SetResult(null), null, millisecondsDelay, Timeout.Infinite);

    // Create and return a task that will be scheduled when the trigger fires.
    return tcs.Task.ContinueWith(_ =>
    {
        timer.Dispose();
        action();
    });
}

이는 작업을 지나치게 단순화하는 것일 수 있지만 작업 완료 소스를 사용하면 이벤트를 대기할 수 있습니다.tcs 이후로.SetResult는 이벤트가 발생한 후에만 설정되며, 호출자는 작업을 기다릴 수 있습니다.

자세한 내용은 이 비디오를 참조하십시오.

http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Lucian03-TipsForAsyncThreadsAndDatabinding

는 현실 해 본 적이 .TaskCompletionSource다운로드 대기열을 구현할 때입니다.를 시작하면 한 합니다.TaskCompletionSource다운로드가 완료되면 작동 중인 스레드가 작업을 완료합니다.

여기서 핵심 개념은 클라이언트가 작업을 실제로 시작할 때부터 시작하도록 요청할 때 제가 디커플링을 한다는 것입니다.이 경우에는 클라이언트가 리소스 관리를 처리하는 것을 원하지 않기 때문입니다.

C#5 컴파일러(VS 2012+)를 사용하는 한 .net 4에서 비동기/대기를 사용할 수 있습니다. 자세한 내용은 여기를 참조하십시오.

사용한 적이 있습니다.TaskCompletionSource취소될 때까지 작업을 실행합니다.이 경우 응용 프로그램이 실행되는 동안 일반적으로 실행하려는 서비스 버스 가입자입니다.

public async Task RunUntilCancellation(
    CancellationToken cancellationToken,
    Func<Task> onCancel)
{
    var doneReceiving = new TaskCompletionSource<bool>();

    cancellationToken.Register(
        async () =>
        {
            await onCancel();
            doneReceiving.SetResult(true); // Signal to quit message listener
        });

    await doneReceiving.Task.ConfigureAwait(false); // Listen until quit signal is received.
}

블레이저의 웹 어셈블리또한 호스트는 이 기능을 사용하여 을(를) 방지합니다.NET VM 중지.

await new TaskCompletionSource().Task;

언급URL : https://stackoverflow.com/questions/15316613/when-should-taskcompletionsourcet-be-used

반응형