我是c#的新手;我主要做了Java。
我想实现一个超时的东西:
int now= Time.now();
while(true)
{
tryMethod();
if(now > now+5000) throw new TimeoutException();
}
如何在C#中实现这一点?谢谢!
答案 0 :(得分:36)
一种可能的方式是:
Stopwatch sw = new Stopwatch();
sw.Start();
while(true)
{
tryMethod();
if(sw.ElapsedMilliseconds > 5000) throw new TimeoutException();
}
但是你现在无法摆脱你的循环。我建议让tryMethod
返回bool
并将其更改为:
Stopwatch sw = new Stopwatch();
sw.Start();
while(!tryMethod())
{
if(sw.ElapsedMilliseconds > 5000) throw new TimeoutException();
}
答案 1 :(得分:6)
我认为您可以使用计时器和委托执行此操作,我的示例代码如下:
using System;
using System.Timers;
class Program
{
public delegate void tm();
static void Main(string[] args)
{
var t = new tm(tryMethod);
var timer = new Timer();
timer.Interval = 5000;
timer.Start();
timer.Elapsed += (sender, e) => timer_Elapsed(t);
t.BeginInvoke(null, null);
}
static void timer_Elapsed(tm p)
{
p.EndInvoke(null);
throw new TimeoutException();
}
static void tryMethod()
{
Console.WriteLine("FooBar");
}
}
您有tryMethod,然后创建一个委托并将此委托指向tryMethod,然后以异步方式启动此委托。然后你有一个计时器,Interval是5000ms,你将你的委托传递给你的计时器经过的方法(它应该作为一个委托是一个参考类型,而不是一个值类型),一旦5000秒过去,你调用EndInvoke代表的方法。
答案 2 :(得分:2)
只要tryMethod()没有阻止,这应该做你想要的:
在移动时不适合夏令时或更改时区:
DateTime startTime = DateTime.Now;
while(true)
{
tryMethod();
if(DateTime.Now.Subtract(startTime).TotalMilliseconds > 5000)
throw new TimeoutException();
}
时区和夏令时安全版本:
DateTime startTime = DateTime.UtcNow;
while(true)
{
tryMethod();
if(DateTime.UtcNow.Subtract(startTime).TotalMilliseconds > 5000)
throw new TimeoutException();
}
(DateTimeOffset需要.NET 3.5或更高版本。)
DateTimeOffset startTime = DateTimeOffset.Now;
while(true)
{
tryMethod();
if(DateTimeOffset.Now.Subtract(startTime).TotalMilliseconds > 5000)
throw new TimeoutException();
}
答案 3 :(得分:2)
这里我实现了一个自定义类,其中包含一个将任务包装为超时的方法。
await new TaskWithTimeoutWrapper().RunWithCustomTimeoutAsync(10000, () => this.MyTask());
然后你可以这样称呼它:
var myResult = await new TaskWithTimeoutWrapper().RunWithCustomTimeoutAsync(10000, () => this.MyTaskThatReturnsMyResult());
或
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_main_queue(), ^{
self.tableView.contentOffset = CGPointMake(0, -20);
});
}
如果要在超时时取消正在运行的异步任务,可以添加取消令牌。
希望有所帮助
答案 4 :(得分:1)
我喜欢这样做的另一种方式:
public class TimeoutAction
{
private Thread ActionThread { get; set; }
private Thread TimeoutThread { get; set; }
private AutoResetEvent ThreadSynchronizer { get; set; }
private bool _success;
private bool _timout;
/// <summary>
///
/// </summary>
/// <param name="waitLimit">in ms</param>
/// <param name="action">delegate action</param>
public TimeoutAction(int waitLimit, Action action)
{
ThreadSynchronizer = new AutoResetEvent(false);
ActionThread = new Thread(new ThreadStart(delegate
{
action.Invoke();
if (_timout) return;
_timout = true;
_success = true;
ThreadSynchronizer.Set();
}));
TimeoutThread = new Thread(new ThreadStart(delegate
{
Thread.Sleep(waitLimit);
if (_success) return;
_timout = true;
_success = false;
ThreadSynchronizer.Set();
}));
}
/// <summary>
/// If the action takes longer than the wait limit, this will throw a TimeoutException
/// </summary>
public void Start()
{
ActionThread.Start();
TimeoutThread.Start();
ThreadSynchronizer.WaitOne();
if (!_success)
{
throw new TimeoutException();
}
ThreadSynchronizer.Close();
}
}
答案 5 :(得分:1)
这个问题已经很老了,但是还有另一个选择。
using(CancellationTokenSource cts = new CancellationTokenSource(5000))
{
cts.Token.Register(() => { throw new TimeoutException(); });
while(!cts.IsCancellationRequested)
{
tryMethod();
}
}
从技术上讲,您还应该在CancellationToken
中传播tryMethod()
,以使其间断。
正在运行的演示:(请注意,由于.netfiddle不喜欢它,因此我不得不删除了引发异常的行为。)
答案 6 :(得分:0)
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(10000);
try
{
Task task = Task.Run(() => { methodToTimeoutAfter10Seconds(); }, cts.Token);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
using (cts.Token.Register(s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs))
{
if (task != await Task.WhenAny(task, tcs.Task))
{
throw new OperationCanceledException(cts.Token);
}
}
/* Wait until the task is finish or timeout. */
task.Wait();
/* Rest of the code goes here */
}
catch (TaskCanceledException)
{
Console.WriteLine("Timeout");
}
catch (OperationCanceledException)
{
Console.WriteLine("Timeout");
}
catch (Exception ex)
{
Console.WriteLine("Other exceptions");
}
finally
{
cts.Dispose();
}