Task.waitAny функциональность для ожидающих - PullRequest
0 голосов
/ 26 февраля 2020

Я сейчас нахожусь в состоянии гонки из-за ожидания в течение 0,25 секунд в асинхронной функции c. Токен отмены проверяется в l oop, но происходит поздно из-за ожидания.

Я использую библиотеку, которая предоставляет функциональность Await.Until, которая позволяет ожидать логических значений. Поэтому я подумал, что ожидание либо 0,25 секунды, либо token.isCancelled будет иметь значение true.

Я уверен, что аутсорсинг их для разделения задач, а затем использование Task.waitAny () будет работать, но, похоже, немного поверх. Существует ли более элегантный способ ожидания нескольких ожидаемых объектов?

while (!Completed)
{
    Completed = AdjustPath();

    await Await.Seconds(PathingDelay);

    if (!loop) 
        return Completed;
    else if (token.IsCancellationRequested)
    {
        StopMove();

        return false;
    }
}

Проблема, описанная выше, заключается в том, что содержащая функция вызывается снова, которая устанавливает конечный пункт перед разрешением отмены, который останавливает объект и удаляет объект пункт назначения. Хотя я мог бы дождаться завершения задачи, это добавило бы задержку к запуску метода, что не идеально.

Ответы [ 2 ]

1 голос
/ 26 февраля 2020

С помощью TaskCompletionSource<T> вы можете построить Task, который будет завершен, когда заданный CancellationToken.

public static class Async
{
    private static readonly TaskCompletionSource<bool> _neverComplete = new TaskCompletionSource<bool>();

    public static Task CompleteOnCancellation( CancellationToken token )
    {
        if ( !token.CanBeCanceled )
            return _neverComplete.Task;
        if ( token.IsCancellationRequested )
            return Task.CompletedTask;

        var tcs = new TaskCompletionSource<bool>();

        token.Register( () => tcs.SetResult( true ) );

        return tcs.Task;
    }
}

завершит запрос. Теперь вы можете использовать Task.WhenAny, чтобы прервать ожидание. задержка

using var cts = new CancellationTokenSource( 100 );

var longWaitingTask = Task.Delay( 250 );
var cancellationTask = Async.CompleteOnCancellation( cts.Token );

var completedTask = await Task.WhenAny( longWaitingTask, cancellationTask );

if ( completedTask == longWaitingTask )
{
    Console.WriteLine( "Long Running Task completed." );
}
if ( completedTask == cancellationTask )
{
    Console.WriteLine( "Cancellation Task completed." );
}
0 голосов
/ 26 февраля 2020

Использование Задержка (TimeSpan, CancellationToken) , как Дмитрий уже предложил в своем комментарии.

while (!Completed)
{
    Completed = AdjustPath();

    try
    {
        await Task.Delay(PathingDelay, token);
    }
    catch(TaskCanceledException e){} // if delay was cancelled is checked in next lines

    if (!loop) 
        return Completed;
    else if (token.IsCancellationRequested)
    {
        StopMove();

        return false;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...