작업 이 시간 초과와 함께 완료될 때 까지 비동기적으로 대기
작업을 기다리고 싶습니다. <몇 가지 특별한 규칙으로 완료하기:X밀리초가 지나도 완료되지 않으면 사용자에게 메시지를 표시하고 싶습니다.그리고 Y밀리초가 지나도 완료되지 않으면 자동으로 취소 요청을 하고 싶습니다.
작업을 사용할 수 있습니다.계속에서 작업이 완료될 때까지 비동기적으로 대기(즉, 작업이 완료될 때 실행되도록 작업을 예약)하지만 시간 제한을 지정할 수는 없습니다.작업을 사용할 수 있습니다.작업이 시간 초과와 함께 완료될 때까지 동시에 대기하지만 이 경우 스레드가 차단됩니다.작업이 완료되고 시간이 초과될 때까지 비동기적으로 기다리는 방법은 무엇입니까?
이거 어때:
int timeout = 1000;
var task = SomeOperationAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
그리고 여기 "Crafting a Task"라는 멋진 블로그 게시물이 있습니다.(MS Parallel Library team의) 이러한 종류의 것에 대한 자세한 내용은 다음과 같습니다.
추가: 제 답변에 대한 의견 요청에 따라 취소 처리를 포함한 확장된 솔루션이 있습니다.작업 및 타이머에 취소를 전달하는 것은 코드에서 취소가 발생할 수 있는 여러 가지 방법이 있음을 의미하며, 모든 취소를 올바르게 처리하는지 테스트하고 확신해야 합니다.다양한 조합에 의존하지 말고 컴퓨터가 런타임에 올바른 작업을 수행하기를 바랍니다.
int timeout = 1000;
var task = SomeOperationAsync(cancellationToken);
if (await Task.WhenAny(task, Task.Delay(timeout, cancellationToken)) == task)
{
// Task completed within timeout.
// Consider that the task may have faulted or been canceled.
// We re-await the task so that any exceptions/cancellation is rethrown.
await task;
}
else
{
// timeout/cancellation logic
}
Andrew Arnott가 답변에 대한 코멘트에서 제안한 대로 원래 작업이 완료될 때 시간 초과를 취소하는 확장 방법 버전이 있습니다.
public static async Task<TResult> TimeoutAfter<TResult>(this Task<TResult> task, TimeSpan timeout) {
using (var timeoutCancellationTokenSource = new CancellationTokenSource()) {
var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token));
if (completedTask == task) {
timeoutCancellationTokenSource.Cancel();
return await task; // Very important in order to propagate exceptions
} else {
throw new TimeoutException("The operation has timed out.");
}
}
}
.Net 6(Preview 7) 이상부터는 새로운 내장 메서드 태스크가 있습니다.Async가 이를 달성할 때까지 기다립니다.
// Using TimeSpan
await myTask.WaitAsync(TimeSpan.FromSeconds(10));
// Using CancellationToken
await myTask.WaitAsync(cancellationToken);
// Using both TimeSpan and CancellationToken
await myTask.WaitAsync(TimeSpan.FromSeconds(10), cancellationToken);
이 완료되기 전에 완료되지 않은 경우TimeSpan
또는CancellationToken
그러면 그것은 던집니다.TimeoutException
또는TaskCanceledException
각각 다음과 같다.
try
{
await myTask.WaitAsync(TimeSpan.FromSeconds(10), cancellationToken);
}
catch (TaskCanceledException)
{
Console.WriteLine("Task didn't get finished before the `CancellationToken`");
}
catch (TimeoutException)
{
Console.WriteLine("Task didn't get finished before the `TimeSpan`");
}
사용할 수 있습니다.Task.WaitAny
여러 작업 중 첫 번째 작업을 대기합니다.
작업된 시간 초과 후 을 " " " " " " " " ( " " " ( " " " ( " " " " " 을 사용할 수 .WaitAny
어떤 것이든 먼저 완료되기를 기다립니다.먼저 완료한 작업이 "작업" 작업이면 완료됩니다.먼저 완료한 작업이 시간 초과 작업인 경우 시간 초과에 대응할 수 있습니다(예: 취소 요청).
이것은 이전 답변의 약간 향상된 버전입니다.
- 로렌스의 답변 외에도 시간 초과가 발생하면 원래 작업을 취소합니다.
- sjb의 답변 변형 2 및 3 이외에도 다음과 같은 기능을 제공할 수 있습니다.
CancellationToken
할 때, 은 원래작경우, 고시발초면생하가과간의업그리,발면하▁for생,▁occurs▁get가,TimeoutException
에OperationCanceledException
.
async Task<TResult> CancelAfterAsync<TResult>(
Func<CancellationToken, Task<TResult>> startTask,
TimeSpan timeout, CancellationToken cancellationToken)
{
using (var timeoutCancellation = new CancellationTokenSource())
using (var combinedCancellation = CancellationTokenSource
.CreateLinkedTokenSource(cancellationToken, timeoutCancellation.Token))
{
var originalTask = startTask(combinedCancellation.Token);
var delayTask = Task.Delay(timeout, timeoutCancellation.Token);
var completedTask = await Task.WhenAny(originalTask, delayTask);
// Cancel timeout to stop either task:
// - Either the original task completed, so we need to cancel the delay task.
// - Or the timeout expired, so we need to cancel the original task.
// Canceling will not affect a task, that is already completed.
timeoutCancellation.Cancel();
if (completedTask == originalTask)
{
// original task completed
return await originalTask;
}
else
{
// timeout
throw new TimeoutException();
}
}
}
사용.
InnerCallAsync
완료하는 데 시간이 오래 걸릴 수 있습니다. CallAsync
시간 초과로 래핑합니다.
async Task<int> CallAsync(CancellationToken cancellationToken)
{
var timeout = TimeSpan.FromMinutes(1);
int result = await CancelAfterAsync(ct => InnerCallAsync(ct), timeout,
cancellationToken);
return result;
}
async Task<int> InnerCallAsync(CancellationToken cancellationToken)
{
return 42;
}
Stephen Cleary의 우수한 AsyncEx 라이브러리를 사용하여 다음 작업을 수행할 수 있습니다.
TimeSpan timeout = TimeSpan.FromSeconds(10);
using (var cts = new CancellationTokenSource(timeout))
{
await myTask.WaitAsync(cts.Token);
}
TaskCanceledException
시간 초과 시 던집니다.
다음은 투표된 상위 답변을 기반으로 완전히 작동한 예입니다.
int timeout = 1000;
var task = SomeOperationAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
이 답변의 구현의 주요 이점은 제네릭이 추가되어 함수(또는 작업)가 값을 반환할 수 있다는 것입니다.즉, 모든 기존 함수를 시간 초과 함수로 래핑할 수 있습니다. 예를 들어, 다음과 같습니다.
이전:
int x = MyFunc();
이후:
// Throws a TimeoutException if MyFunc takes more than 1 second
int x = TimeoutAfter(MyFunc, TimeSpan.FromSeconds(1));
이 코드는 를 필요로 합니다.NET 4.5.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskTimeout
{
public static class Program
{
/// <summary>
/// Demo of how to wrap any function in a timeout.
/// </summary>
private static void Main(string[] args)
{
// Version without timeout.
int a = MyFunc();
Console.Write("Result: {0}\n", a);
// Version with timeout.
int b = TimeoutAfter(() => { return MyFunc(); },TimeSpan.FromSeconds(1));
Console.Write("Result: {0}\n", b);
// Version with timeout (short version that uses method groups).
int c = TimeoutAfter(MyFunc, TimeSpan.FromSeconds(1));
Console.Write("Result: {0}\n", c);
// Version that lets you see what happens when a timeout occurs.
try
{
int d = TimeoutAfter(
() =>
{
Thread.Sleep(TimeSpan.FromSeconds(123));
return 42;
},
TimeSpan.FromSeconds(1));
Console.Write("Result: {0}\n", d);
}
catch (TimeoutException e)
{
Console.Write("Exception: {0}\n", e.Message);
}
// Version that works on tasks.
var task = Task.Run(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(1));
return 42;
});
// To use async/await, add "await" and remove "GetAwaiter().GetResult()".
var result = task.TimeoutAfterAsync(TimeSpan.FromSeconds(2)).
GetAwaiter().GetResult();
Console.Write("Result: {0}\n", result);
Console.Write("[any key to exit]");
Console.ReadKey();
}
public static int MyFunc()
{
return 42;
}
public static TResult TimeoutAfter<TResult>(
this Func<TResult> func, TimeSpan timeout)
{
var task = Task.Run(func);
return TimeoutAfterAsync(task, timeout).GetAwaiter().GetResult();
}
private static async Task<TResult> TimeoutAfterAsync<TResult>(
this Task<TResult> task, TimeSpan timeout)
{
var result = await Task.WhenAny(task, Task.Delay(timeout));
if (result == task)
{
// Task completed within timeout.
return task.GetAwaiter().GetResult();
}
else
{
// Task timed out.
throw new TimeoutException();
}
}
}
}
주의사항
이 대답을 듣고 일반적으로 정상 작동 중에 예외를 코드에 넣는 것은 다음과 같은 경우를 제외하고는 일반적으로 좋지 않습니다.
- 예외가 발생할 때마다 매우 무거운 작업입니다.
- 예외가 엄격한 루프에 있는 경우 예외는 코드 속도를 100배 이상 늦출 수 있습니다.
호출 중인 기능을 특정 시간 이후에 시간 초과되도록 변경할 수 없는 경우에만 이 코드를 사용하십시오.TimeSpan
.
이 답변은 시간 초과 매개 변수를 포함하도록 리팩터링할 수 없는 타사 라이브러리를 다룰 때만 적용할 수 있습니다.
강력한 코드를 작성하는 방법
강력한 코드를 작성하려면 일반적인 규칙은 다음과 같습니다.
잠재적으로 무기한 차단될 수 있는 모든 작업에는 시간 초과가 있어야 합니다.
이 규칙을 준수하지 않으면 코드가 어떤 이유로 실패한 작업에 도달하고 무기한 차단되며 앱이 영구적으로 중단됩니다.
일정 시간 후에 적절한 시간 초과가 발생하면 앱이 과도한 시간(예: 30초) 동안 중단된 후 오류를 표시하고 계속 진행하거나 다시 시도합니다.
이런 건 어때요?
const int x = 3000;
const int y = 1000;
static void Main(string[] args)
{
// Your scheduler
TaskScheduler scheduler = TaskScheduler.Default;
Task nonblockingTask = new Task(() =>
{
CancellationTokenSource source = new CancellationTokenSource();
Task t1 = new Task(() =>
{
while (true)
{
// Do something
if (source.IsCancellationRequested)
break;
}
}, source.Token);
t1.Start(scheduler);
// Wait for task 1
bool firstTimeout = t1.Wait(x);
if (!firstTimeout)
{
// If it hasn't finished at first timeout display message
Console.WriteLine("Message to user: the operation hasn't completed yet.");
bool secondTimeout = t1.Wait(y);
if (!secondTimeout)
{
source.Cancel();
Console.WriteLine("Operation stopped!");
}
}
});
nonblockingTask.Start();
Console.WriteLine("Do whatever you want...");
Console.ReadLine();
}
태스크를 사용할 수 있습니다.다른 작업을 사용하여 주 스레드를 차단하지 않고 대기 옵션.
타이머를 사용하여 메시지 및 자동 취소를 처리합니다.작업이 완료되면 타이머가 실행되지 않도록 타이머에 대해 폐기를 호출합니다.다음은 예제입니다. 작업지연을 500, 1500 또는 2500로 변경하여 다양한 경우를 확인합니다.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
private static Task CreateTaskWithTimeout(
int xDelay, int yDelay, int taskDelay)
{
var cts = new CancellationTokenSource();
var token = cts.Token;
var task = Task.Factory.StartNew(() =>
{
// Do some work, but fail if cancellation was requested
token.WaitHandle.WaitOne(taskDelay);
token.ThrowIfCancellationRequested();
Console.WriteLine("Task complete");
});
var messageTimer = new Timer(state =>
{
// Display message at first timeout
Console.WriteLine("X milliseconds elapsed");
}, null, xDelay, -1);
var cancelTimer = new Timer(state =>
{
// Display message and cancel task at second timeout
Console.WriteLine("Y milliseconds elapsed");
cts.Cancel();
}
, null, yDelay, -1);
task.ContinueWith(t =>
{
// Dispose the timers when the task completes
// This will prevent the message from being displayed
// if the task completes before the timeout
messageTimer.Dispose();
cancelTimer.Dispose();
});
return task;
}
static void Main(string[] args)
{
var task = CreateTaskWithTimeout(1000, 2000, 2500);
// The task has been started and will display a message after
// one timeout and then cancel itself after the second
// You can add continuations to the task
// or wait for the result as needed
try
{
task.Wait();
Console.WriteLine("Done waiting for task");
}
catch (AggregateException ex)
{
Console.WriteLine("Error waiting for task:");
foreach (var e in ex.InnerExceptions)
{
Console.WriteLine(e);
}
}
}
}
}
또한 비동기 CTP는 TaskEx를 제공합니다.태스크에서 타이머를 래핑하는 지연 방법입니다.이렇게 하면 타이머가 실행될 때 작업 스케줄러를 계속 설정하는 것과 같은 작업을 더 잘 제어할 수 있습니다.
private static Task CreateTaskWithTimeout(
int xDelay, int yDelay, int taskDelay)
{
var cts = new CancellationTokenSource();
var token = cts.Token;
var task = Task.Factory.StartNew(() =>
{
// Do some work, but fail if cancellation was requested
token.WaitHandle.WaitOne(taskDelay);
token.ThrowIfCancellationRequested();
Console.WriteLine("Task complete");
});
var timerCts = new CancellationTokenSource();
var messageTask = TaskEx.Delay(xDelay, timerCts.Token);
messageTask.ContinueWith(t =>
{
// Display message at first timeout
Console.WriteLine("X milliseconds elapsed");
}, TaskContinuationOptions.OnlyOnRanToCompletion);
var cancelTask = TaskEx.Delay(yDelay, timerCts.Token);
cancelTask.ContinueWith(t =>
{
// Display message and cancel task at second timeout
Console.WriteLine("Y milliseconds elapsed");
cts.Cancel();
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(t =>
{
timerCts.Cancel();
});
return task;
}
.Net 6(답변 날짜 미리보기 7)을 사용하면 새로운 WaitAsync(시간 범위, 취소)를 사용할 수 있습니다.토큰)은 이러한 특정 요구에 대한 답변입니다.만약 당신이 사용할 수 있다면.Net6, 이 버전은 또한 이 게시물에서 제안된 대부분의 좋은 솔루션과 비교하면 최적화된 것으로 설명됩니다.
(여러 해 동안 귀사의 솔루션을 사용해 왔기 때문에 모든 참가자에게 감사드립니다.)
이 문제를 해결하는 또 다른 방법은 반응형 확장을 사용하는 것입니다.
public static Task TimeoutAfter(this Task task, TimeSpan timeout, IScheduler scheduler)
{
return task.ToObservable().Timeout(timeout, scheduler).ToTask();
}
유닛 테스트에서 아래 코드를 사용하여 위의 테스트를 수행하십시오. 저에게 효과가 있습니다.
TestScheduler scheduler = new TestScheduler();
Task task = Task.Run(() =>
{
int i = 0;
while (i < 5)
{
Console.WriteLine(i);
i++;
Thread.Sleep(1000);
}
})
.TimeoutAfter(TimeSpan.FromSeconds(5), scheduler)
.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnFaulted);
scheduler.AdvanceBy(TimeSpan.FromSeconds(6).Ticks);
다음 네임스페이스가 필요할 수 있습니다.
using System.Threading.Tasks;
using System.Reactive.Subjects;
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
using Microsoft.Reactive.Testing;
using System.Threading;
using System.Reactive.Concurrency;
반응형 확장을 사용하는 위의 @Kevan 답변의 일반 버전입니다.
public static Task<T> TimeoutAfter<T>(this Task<T> task, TimeSpan timeout, IScheduler scheduler)
{
return task.ToObservable().Timeout(timeout, scheduler).ToTask();
}
선택적 스케줄러 포함:
public static Task<T> TimeoutAfter<T>(this Task<T> task, TimeSpan timeout, Scheduler scheduler = null)
{
return scheduler is null
? task.ToObservable().Timeout(timeout).ToTask()
: task.ToObservable().Timeout(timeout, scheduler).ToTask();
}
BTW: 시간 초과가 발생하면 시간 초과 예외가 발생합니다.
재미삼아 'On Timeout'을 Task로 확장했습니다.시간 초과 시 작업은 원하는 인라인 람다 작업()을 실행하고 true를 반환하며 그렇지 않으면 false를 반환합니다.
public static async Task<bool> OnTimeout<T>(this T t, Action<T> action, int waitms) where T : Task
{
if (!(await Task.WhenAny(t, Task.Delay(waitms)) == t))
{
action(t);
return true;
} else {
return false;
}
}
OnTimeout 확장은 UDP 소켓 비동기를 호출하는 예제와 같이 변수에 할당할 수 있는 bool 결과를 반환합니다.
var t = UdpSocket.ReceiveAsync();
var timeout = await t.OnTimeout(task => {
Console.WriteLine("No Response");
}, 5000);
'task' 변수는 시간 초과 람다에서 추가 처리를 위해 액세스할 수 있습니다.
객체 수신 작업을 사용하면 다른 다양한 확장 설계에 영향을 줄 수 있습니다.
작업 또는 지연이 완료될 때까지 대기할 확장을 만듭니다.지연이 승리할 경우 예외를 던집니다.
public static async Task<TResult> WithTimeout<TResult>(this Task<TResult> task, TimeSpan timeout)
{
if (await Task.WhenAny(task, Task.Delay(timeout)) != task)
throw new TimeoutException();
return await task;
}
나는 느꼈습니다.Task.Delay()
및 스크및CancellationTokenSource
다른 답변에서는 엄격한 네트워킹 루프에서 제 사용 사례에 대해 약간 많은 답변을 제공합니다.
비록 조 호그가 임무를 짜고 있지만 말입니다.MSDN 블로그의 방법이 영감을 준 후 타임아웃을 사용하는 것에 약간 싫증이 났습니다.TimeoutException
위와 동일한 이유로 흐름 제어를 위해 시간 초과가 예상되지 않는 경우보다 더 자주 발생합니다.
그래서 저는 블로그에 언급된 최적화도 다루는 이것을 선택했습니다.
public static async Task<bool> BeforeTimeout(this Task task, int millisecondsTimeout)
{
if (task.IsCompleted) return true;
if (millisecondsTimeout == 0) return false;
if (millisecondsTimeout == Timeout.Infinite)
{
await Task.WhenAll(task);
return true;
}
var tcs = new TaskCompletionSource<object>();
using (var timer = new Timer(state => ((TaskCompletionSource<object>)state).TrySetCanceled(), tcs,
millisecondsTimeout, Timeout.Infinite))
{
return await Task.WhenAny(task, tcs.Task) == task;
}
}
사용 사례의 예는 다음과 같습니다.
var receivingTask = conn.ReceiveAsync(ct);
while (!await receivingTask.BeforeTimeout(keepAliveMilliseconds))
{
// Send keep-alive
}
// Read and do something with data
var data = await receivingTask;
Andrew Arnott의 대답의 몇 가지 변형:
기존 작업을 기다려 완료되었는지 또는 시간 초과되었는지 확인하고 싶지만 시간 초과가 발생한 경우 취소하지 않으려면 다음을 수행합니다.
public static async Task<bool> TimedOutAsync(this Task task, int timeoutMilliseconds) { if (timeoutMilliseconds < 0 || (timeoutMilliseconds > 0 && timeoutMilliseconds < 100)) { throw new ArgumentOutOfRangeException(); } if (timeoutMilliseconds == 0) { return !task.IsCompleted; // timed out if not completed } var cts = new CancellationTokenSource(); if (await Task.WhenAny( task, Task.Delay(timeoutMilliseconds, cts.Token)) == task) { cts.Cancel(); // task completed, get rid of timer await task; // test for exceptions or task cancellation return false; // did not timeout } else { return true; // did timeout } }
작업을 시작하고 시간 초과가 발생한 경우 작업을 취소하려면 다음을 수행합니다.
public static async Task<T> CancelAfterAsync<T>( this Func<CancellationToken,Task<T>> actionAsync, int timeoutMilliseconds) { if (timeoutMilliseconds < 0 || (timeoutMilliseconds > 0 && timeoutMilliseconds < 100)) { throw new ArgumentOutOfRangeException(); } var taskCts = new CancellationTokenSource(); var timerCts = new CancellationTokenSource(); Task<T> task = actionAsync(taskCts.Token); if (await Task.WhenAny(task, Task.Delay(timeoutMilliseconds, timerCts.Token)) == task) { timerCts.Cancel(); // task completed, get rid of timer } else { taskCts.Cancel(); // timer completed, get rid of task } return await task; // test for exceptions or task cancellation }
시간 초과가 발생한 경우 취소할 태스크가 이미 생성된 경우:
public static async Task<T> CancelAfterAsync<T>(this Task<T> task, int timeoutMilliseconds, CancellationTokenSource taskCts) { if (timeoutMilliseconds < 0 || (timeoutMilliseconds > 0 && timeoutMilliseconds < 100)) { throw new ArgumentOutOfRangeException(); } var timerCts = new CancellationTokenSource(); if (await Task.WhenAny(task, Task.Delay(timeoutMilliseconds, timerCts.Token)) == task) { timerCts.Cancel(); // task completed, get rid of timer } else { taskCts.Cancel(); // timer completed, get rid of task } return await task; // test for exceptions or task cancellation }
시간 초과가 발생하지 않으면 타이머가 취소되므로 여러 번 호출해도 타이머가 쌓이지 않습니다.
sjb
그래서 이것은 오래된 것이지만, 훨씬 더 나은 현대적인 해결책이 있습니다.어떤 버전의 c#/인지 확실하지 않습니다.NET이 필요하지만 다음과 같이 해야 합니다.
... Other method code not relevant to the question.
// a token source that will timeout at the specified interval, or if cancelled outside of this scope
using var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5));
using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, timeoutTokenSource.Token);
async Task<MessageResource> FetchAsync()
{
try
{
return await MessageResource.FetchAsync(m.Sid);
} catch (TaskCanceledException e)
{
if (timeoutTokenSource.IsCancellationRequested)
throw new TimeoutException("Timeout", e);
throw;
}
}
return await Task.Run(FetchAsync, linkedTokenSource.Token);
그CancellationTokenSource
생성자가 사용합니다.TimeSpan
매개 변수입니다. 이 매개 변수는 해당 간격이 경과한 후 해당 토큰을 취소합니다.그런 다음 비동기(또는 동기) 코드를 다른 호출로 감쌀 수 있습니다.Task.Run
시간 초과 토큰을 전달합니다.
이것은 당신이 취소 토큰을 전달한다고 가정합니다.token
변수).시간 초과와 별도로 작업을 취소할 필요가 없는 경우 다음을 사용할 수 있습니다.timeoutTokenSource
직접적으로.그렇지 않으면 다음을 생성합니다.linkedTokenSource
시간 초과가 발생하거나 그렇지 않으면 취소됩니다.
그러면 우리는 그냥 잡습니다.OperationCancelledException
그리고 어떤 토큰이 예외를 던졌는지 확인하고, 던집니다.TimeoutException
시간 초과로 인해 문제가 발생한 경우.그렇지 않으면, 우리는 버려집니다.
또한 여기서는 C# 7에 소개된 로컬 함수를 사용하고 있지만 람다 함수나 실제 함수를 동일한 효과로 쉽게 사용할 수 있습니다.마찬가지로, c#8은 문을 사용하기 위한 더 간단한 구문을 도입했지만, 문을 다시 쓰기에 충분히 쉽습니다.
Blocking Collection을 사용하여 작업을 예약하면 생산자는 잠재적으로 오래 실행되는 작업을 실행할 수 있고 소비자는 시간 초과 및 취소 토큰이 내장된 TryTake 메서드를 사용할 수 있습니다.
저는 여기에 있는 다른 답변들과 다른 스레드에 있는 이 답변들의 아이디어를 Try 스타일의 확장 방법으로 재조합하고 있습니다.이것은 확장 방법을 원하지만 시간 초과 시 예외가 발생하지 않도록 하는 경우에 유용합니다.
public static async Task<bool> TryWithTimeoutAfter<TResult>(this Task<TResult> task,
TimeSpan timeout, Action<TResult> successor)
{
using var timeoutCancellationTokenSource = new CancellationTokenSource();
var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token))
.ConfigureAwait(continueOnCapturedContext: false);
if (completedTask == task)
{
timeoutCancellationTokenSource.Cancel();
// propagate exception rather than AggregateException, if calling task.Result.
var result = await task.ConfigureAwait(continueOnCapturedContext: false);
successor(result);
return true;
}
else return false;
}
async Task Example(Task<string> task)
{
string result = null;
if (await task.TryWithTimeoutAfter(TimeSpan.FromSeconds(1), r => result = r))
{
Console.WriteLine(result);
}
}
누군가 이런 것을 찾고 있는 경우(OP의 질문 이후 12년).
다른 옵션은 작업만 사용하는 것입니다.다른 작업 내부에서 대기(시간 초과)합니다.실행(). 작업을 사용하지 않으려면 이 옵션을 선택합니다.WaitAny() 또는 대기 호출.아니면 제 경우에는 제가 함께 작업하고 있는 나머지 .cs와의 일관성을 위해서야.
이와 같은 것:
int timeout = 5000;
var actualTask = new Task(() =>
{
// Do your stuff here
});
Task.Run(() =>
{
actualTask.Start();
if (!actualTask.Wait(timeout))
{
return false;
// or throw new TimeoutException("Operation timed out!");
}
return true;
}).ContinueWith((timedTaskResult) =>
{
if (!timedTaskResult.Result)
{
// tell user it timed out!
}
if (timedTaskResult.IsFaulted)
{
// Tell the user about the error/s via the timedTaskResult.Exception
}
});
언급URL : https://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout
'programing' 카테고리의 다른 글
WPF에 기본()이 없습니까? (0) | 2023.05.10 |
---|---|
선호하는 바시쉐방("#!")은 무엇입니까? (0) | 2023.05.10 |
.NET - 프로토콜, 호스트 및 포트 가져오기 (0) | 2023.05.10 |
좋은 질문입니다.NET 개발자는 대답할 수 있어야 합니까? (0) | 2023.05.10 |
SSIS Excel 가져오기 강제 적용 잘못된 열 유형 (0) | 2023.05.10 |