작업 이 시간 초과와 함께 완료될 때 까지 비동기적으로 대기
작업을 기다리고 싶습니다. <몇 가지 특별한 규칙으로 완료하기: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 |