İşte en çok oy alan cevaba dayanan tamamen çalışan bir örnek:
int timeout = 1000;
var task = SomeOperationAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
Bu cevaptaki uygulamanın ana avantajı jeneriklerin eklenmiş olmasıdır, böylece işlev (veya görev) bir değer döndürebilir. Bu, varolan herhangi bir işlevin zaman aşımı işleviyle sarılabileceği anlamına gelir, örneğin:
Önce:
int x = MyFunc();
Sonra:
// Throws a TimeoutException if MyFunc takes more than 1 second
int x = TimeoutAfter(MyFunc, TimeSpan.FromSeconds(1));
Bu kod .NET 4.5 gerektirir.
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();
}
}
}
}
Uyarılar
Bu cevabı verdikten sonra , kesinlikle yapmanız gerekmedikçe, normal çalışma sırasında kodunuzda istisnalar olması iyi bir uygulama değildir :
- Her istisna atıldığında, son derece ağır bir işlemdir,
- İstisnalar sıkı bir döngüde ise istisnalar kodunuzu 100 veya daha fazla faktör yavaşlatabilir.
Bu kodu yalnızca, aradığınız işlevi kesinlikle değiştiremiyorsanız kullanın, böylece belirli bir süreden sonra zaman aşımına uğrar TimeSpan
.
Bu cevap gerçekten sadece bir zaman aşımı parametresi eklemek için yeniden düzenleyemeyeceğiniz 3. taraf kütüphane kütüphaneleri ile uğraşırken geçerlidir.
Sağlam kod nasıl yazılır
Sağlam kod yazmak istiyorsanız, genel kural şudur:
Süresiz olarak engellenebilecek her işlemde zaman aşımı olması gerekir.
Eğer varsa yok bu kurala, kodunuz sonunda nedense, o zaman süresiz engeller başarısız olur ve uygulama sadece kalıcı asılı olan bir operasyonu vuracaktır.
Bir süre sonra makul bir zaman aşımı olsaydı, uygulamanız aşırı bir süre beklerdi (örneğin 30 saniye), bir hata görüntüler ve neşeli yoluna devam eder veya tekrar dener.