方法调用超时

5

原始的方法调用方式如下:

public string AskAPI(string uri)
{
    return api.Query(uri);
}

API只是一个导入的dll引用。

现在,我想给AskAPI方法添加超时功能,如果api.Query花费的时间超过30秒,AskAPI将抛出异常。

似乎我无法让它工作。有人能分享一下他们的想法吗?

谢谢!


你需要能够修改 api.Query 来添加超时功能。由于你没有提供任何关于它的信息,所以无法告诉你如何做到这一点。(在你发布的内容中,没有办法在调用周围设置超时,因为你没有办法基于它来中断它。) - Ken White
@KenWhite api.Query也不在我的控制范围内。你的意思是说,如果不编辑它,我就无法超时AskAPI方法? - jamesdeath123
我无法回答你的问题,因为你仅提供了三行代码({}不算在内),没有任何其他背景信息。根据你所提供的信息,答案是“不行”。 - Ken White
1个回答

8
您可以使用Tasks 来实现此功能,以下为示例代码:

public string AskAPI(string uri, int millis)
{
    using (var task = new Task<string>(() => api.Query(uri)))
    {
        task.Start();
        task.Wait(millis);
        if (!task.IsCompleted) throw new TimeoutException();
        return task.Result;
    }   
}

感谢Guillaume建议使用TimeoutException。
但是,正如Jim Mischel指出的那样,这不会阻止任务完成,在这种情况下,最好修改您正在调用的API,因为这样您就可以充分利用为此而设计的CancellationToken类。
除此之外,我能想到的唯一其他快速解决方法(可能不可取)是将该方法包装起来(或与某些内容结合),如下所示:
public T Await<T>(Func<T> fun, int millis)
{
    using (var cancel = new CancellationTokenSource(millis))
    using (var task = new Task<T>(() =>
    {
        T result = default(T);
        var thread = new Thread(() => result = fun());
        thread.Start();
        while (!cancel.Token.IsCancellationRequested && thread.IsAlive) ; // Wait for a sign from above
        thread.Abort();
        cancel.Token.ThrowIfCancellationRequested();
        return result;
    }, cancel.Token))
    {
        task.Start();
        task.Wait(millis);
        cancel.Cancel();
        if (!task.IsCompleted) throw new TimeoutException();
        return task.Result;
    }
}

然后使用以下方式调用:

Await(() => AskAPI("http://some.uri"), 30000);

1
不要抛出“Exception”。抛出“TimeoutException”。 - Guillaume
1
@Guillaume 谢谢你,我应该花时间去查一下的。=) - sgbj
2
但任务仍在执行,对吗?也就是说,api.Query 没有被中止? - Jim Mischel
这似乎是对我的问题最好的实际方法。 - jamesdeath123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接