Nie trzeba rozpocząć długą zadanie wydajność dla tego - po prostu zrobić swoje metody asynchronicznego bezpośrednio:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token)
{
while(true)
{
await Task.Delay(pollInterval, token);
action();
}
}
To spowoduje Action
do uruchomienia na bieżącym kontekście. Jeśli nie jest to wymagane, można użyć:
await Task.Delay(pollInterval, token).ConfigureAwait(false);
action();
To spowoduje Action
aby nie działać na tym samym kontekście synchronizacji rozmówcy i potencjalnie użyć wątku puli wątków.
Edycja w odpowiedzi na komentarze:
Jeśli nie chcesz wynikowy zadanie wrócić odwołany, ale po prostu wrócić, gdy znacznik jest zwolniony, można użyć:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token)
{
while(!token.IsCancellationRequested)
{
try
{
await Task.Delay(pollInterval, token);
action();
}
catch(OperationCanceledException e)
{
// Swallow cancellation - dangerous if action() throws this, though....
break;
}
}
}
Edit 2:
Jeśli chcesz przekazać w async
lambdas, należy dokonać metoda wziąć Func<Task>
nie Action
:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Func<Task> actionTask, CancellationToken token)
{
while(!token.IsCancellationRequested)
{
try
{
await Task.Delay(pollInterval, token);
}
catch(OperationCanceledException e)
{
// Swallow cancellation
break;
}
await actionTask();
}
}
Edycja w odpowiedzi na czat:
Jeśli chcesz sondować, ale wykorzystać wyniki operacji, można użyć:
public static async Task RunAtIntervalAsync<T>(TimeSpan pollInterval, Func<Task<T>> fetchOperation, Action<T> operationOnResult, CancellationToken token)
{
while(!token.IsCancellationRequested)
{
try
{
await Task.Delay(pollInterval, token);
}
catch(OperationCanceledException e)
{
// Swallow cancellation
break;
}
// Get a value
T value = await fetchOperation();
// Use result (ie: update UI)
operationOnResult(value);
}
}
następnie można nazwać to poprzez:
RunAtIntervalAsync(TimeSpan.FromSeconds(1),
async() => { await Task.Delay(1000); return "Foo"; },
result => UpdateUI(result),
token);
Dlaczego 'Odstęp czasu' zwraca' Zadanie '? Nigdy się nie kończy (trwa tak długo, aż pojawi się wyjątek lub błędy) i nigdy nie ma wartości "T", która jest ustawiona jako wynik. –
Servy
@Servy nie mam token anulowania –
Tak, a jeśli jest anulowane, to zadanie jest ustawione na anulowane. Nadal nie ma * wyniku *. W pewnym momencie jest on zakończony, ale nigdy nie ma "wyniku", który można pobrać. moim celem jest zwrócenie 'Task', a nie' Task 'i powinieneś zaakceptować' Action' zamiast 'Func ', ponieważ odrzucasz wynik działania. –
Servy