C#Xamarin表单-执行任务,超时 [英] C# Xamarin Forms - Executing task, with timeout

查看:81
本文介绍了C#Xamarin表单-执行任务,超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

和其他许多人一样,我需要编写一个返回任务的函数,并且希望该任务在一定时间后自动超时.

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.DelayTask.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-不确定那里的原因.实际上,它是DelayWhenAny的低效率版本.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆