C#Xamarin表单-执行任务,超时 [英] C# Xamarin Forms - Executing task, with timeout
问题描述
和其他许多人一样,我需要编写一个返回任务的函数,并且希望该任务在一定时间后自动超时.
Like many others, I need to write a function that returns a task, and I want that task to automatically time out after a certain period.
初始代码如下:
class MyClass
{
TaskCompletionSource<string> m_source;
public Task<string> GetDataFromServer()
{
m_source = new TaskCompletionSource<string> ();
// System call I have no visibility into, and that doesn't inherently take any
// sort of timeout or cancellation token
ask_server_for_data_and_when_youve_got_it_call(Callback);
return m_source.Task;
}
protected void Callback(string data);
{
// Got the data!
m_source.TrySetResult(data);
}
}
现在,我希望它变得更聪明一些,并在适当的时候超时.为此,我有几种选择:
Now I want this to be a little smarter, and time itself out when appropriate. I have several options for doing this:
class MyClass
{
TaskCompletionSource<string> m_source;
public Task<string> GetDataFromServer(int timeoutInSeconds)
{
m_source = new TaskCompletionSource<string> ();
ask_server_for_data_and_when_youve_got_it_call(Callback);
// Method #1 to set up the timeout:
CancellationToken ct = new CancellationToken ();
CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource (ct);
cts.CancelAfter (timeoutInSeconds * 1000);
cts.Token.Register(() => m_source.TrySetCancelled());
// Method #2 to set up the timeout:
CancellationTokenSource ct2 = new CancellationTokenSource ();
ct2.CancelAfter (timeoutInSeconds * 1000);
ct2.Token.Register (() => m_source.TrySetCancelled());
// Method #3 to set up the timeout:
System.Threading.Tasks.Task.Factory.StartNew (async () =>
{
await System.Threading.Tasks.Task.Delay (timeoutInSeconds * 1000);
m_source.TrySetCancelled();
});
// Method #4 to set up the timeout:
Xamarin.Forms.Device.StartTimer (new TimeSpan (0, 0, timeoutInSeconds),
() => m_source.TrySetCancelled());
return m_source.Task;
}
protected void Callback(string data);
{
// Got the data!
m_source.TrySetResult(data);
}
}
设置超时的4种不同方式的优缺点是什么?例如,我猜测方法2是最轻量"的(需要最少的系统资源)?
What are the plusses and minuses to the 4 different ways of setting up a timeout? For instance, I'm guessing that method #2 is the most "lightweight" (requiring the fewest system resources)?
还有其他方法可以设置我错过的超时时间吗?
Are there other ways to set up a timeout that I've missed?
p.s.
我发现了一条很困难的知识-如果您从主UI线程之外的线程调用GetDataFromServer():
One piece of knowledge I found out the hard way - if you call GetDataFromServer() from a thread besides the main UI thread:
Task.Run(() => await GetDataFromServer());
在iOS上,第四个方法(Xamarin.Forms.Device.StartTimer)永远不会触发
On iOS, the fourth method (Xamarin.Forms.Device.StartTimer) never fires
推荐答案
我认为只使用Task.Delay
和Task.WhenAny
会更容易:
I think it's easier to just use Task.Delay
and Task.WhenAny
:
public async Task<string> GetDataFromServerAsync(int timeoutInSeconds)
{
Task<string> requestTask = GetDataFromServerAsync();
var timeoutTask = Task.Delay(timeoutInSeconds);
var completedTask = await Task.WhenAny(requestTask, timeoutTask);
if (completedTask == timeoutTask)
throw new OperationCanceledException();
return await requestTask;
}
其他方法的缺点:
方法1:无缘无故地创建一个新的CancellationToken
.这只是方法2的效率较低的版本.
Method #1: Creates a new CancellationToken
for no reason. It's just a less-efficient version of Method #2.
方法2:通常,任务完成后,您应该处置Register
的结果.在这种情况下,由于最终会取消CTS,所以它可能会正常工作.
Method #2: Normally, you should be disposing the result of Register
once the task completes. In this case, it would probably work OK since the CTS is always eventually cancelled.
方法3:仅使用StartNew
调用Delay
-不确定那里的原因.实际上,它是Delay
和WhenAny
的低效率版本.
Method #3: Uses StartNew
just to call Delay
- not sure of the reasoning there. It's essentially a less-efficient version of Delay
with WhenAny
.
方法4:可以接受.尽管您确实必须处理TaskCompletionSource<T>
及其怪癖(例如,默认情况下为同步连续).
Method #4: Would be acceptable. Though you do have to deal with TaskCompletionSource<T>
and its quirks (e.g., synchronous continuations by default).
这篇关于C#Xamarin表单-执行任务,超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!