2013-08-29 38 views
5

最初的方法調用是這樣的:定時進行的方法調用

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

其中API是一個簡單的導入的DLL參考。

現在我想爲AskAPI方法添加超時功能,以便如果api.Query花費比30秒更長的時間,AskAPI將拋出一個異常。

似乎我無法讓它工作。任何人都可以分享他們的想法嗎?

謝謝!

+0

你必須能夠修改'api.Query'來添加超時功能。由於您沒有提供關於它是什麼的信息,因此不可能告訴您如何執行此操作。 (沒有辦法在通話過程中超時,因爲根據你在這裏發佈的內容你無法中斷它。) –

+0

@KenWhite api.Query也不在我的控制範圍之內。你的意思是沒有編輯它,我不能超時AskAPI方法? – jamesdeath123

+0

我無法回答這個問題,因爲你已經提供了三行代碼('{}'不計算在內),完全沒有其他信息。根據你發佈的內容,答案將是「不,你不能」。 –

回答

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; 
    } 
} 

感謝紀堯姆的建議使用一個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'不會中止? –