2.1 暂停一段时间

Posted zachchen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2.1 暂停一段时间相关的知识,希望对你有一定的参考价值。

问题
需要让程序(以异步方式)等待一段时间。这在进行单元测试或者实现重试延迟时非常
有用。本解决方案也能用于实现简单的超时。

解决方案
Task 类有一个返回Task 对象的静态函数Delay,这个Task 对象会在指定的时间后完成。

Delay方法的重载:

public static Task Delay(TimeSpan delay);
public static Task Delay(TimeSpan delay, CancellationToken cancellationToken);
public static Task Delay(int millisecondsDelay);
public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken);

书中给出三个例子。
一个是单元测试中,定义一个异步完成的任务,以完成“异步成功”测试。

static async Task<T> DelayResult<T>(T result, TimeSpan delay)
{
    await Task.Delay(delay);
    return result;
}

 

一个是指数退避的简单实现

指数退避是一种重试策略,重试的延迟时间会逐次增加。在访问 Web 服务时,最好的方式就是采用指数退避,它可以防止服务器被太多的重试阻塞。

书中提到实际产品开发中,应对指数退避重试机制有更周密的解决方案。书中推荐了微软企业库中的瞬间错误处理模块(Transient Error Handling Block),在微软Docs中找到了相关文章。
暂时性故障处理 (构建使用 Azure 的真实世界云应用程序):
https://docs.microsoft.com/zh-cn/aspnet/aspnet/overview/developing-apps-with-windows-azure/building-real-world-cloud-apps-with-windows-azure/transient-fault-handling

 static async Task<string> DownloadStringWithRetries(string uri)
        {
            using (var client = new HttpClient())
            {
                // 第 1 次重试前等 1 秒,第 2 次等 2 秒,第 3 次等 4 秒。
                var nextDelay = TimeSpan.FromSeconds(1);
                for (var i = 0; i != 3; ++i)
                {
                    try
                    {                       
                        return await client.GetStringAsync(uri);
                    }
                    catch
                    {
                    }
                    await Task.Delay(nextDelay);
                    nextDelay = nextDelay + nextDelay;
                }
                // 最后重试一次,以便让调用者知道出错信息。
                return await client.GetStringAsync(uri);
            }
        }

 

上述代码实现的是对异步get请求进行多次重试。

最后一个例子,是实现了一个简单的超时功能,当get请求在3秒内没有响应,返回null。

        static async Task<string> DownloadStringWithTimeout(string uri)
        {
            using (var client = new HttpClient())
            {
                var downloadTask = client.GetStringAsync(uri);
                var timeoutTask = Task.Delay(3000);
                var completedTask = await Task.WhenAny(downloadTask, timeoutTask);
                if (completedTask == timeoutTask)
                    return null;
                return await downloadTask;
            }
        }

 

该代码的实现主要是借助于Task.WhenAny方法。
Task.WhenAny的返回值是提供的多个任务中已完成的任务。
如果已完成的任务completedTasktimeoutTask相等,证明最先完成的任务是等待三秒之后完成的任务timeoutTask,也就是说downloadTask没有在三秒内完成。



以上是关于2.1 暂停一段时间的主要内容,如果未能解决你的问题,请参考以下文章

js中怎么让程序暂停一段时间

将新片段添加到后台堆栈是不是会暂停当前片段?

我如何在 Node.js (JavaScript) 中等待? l 需要暂停一段时间

Mediaplayer在切换片段时没有暂停

在 Activity 内部,如何暂停 for 循环以调用片段,然后在按钮单击片段后恢复循环以重新开始

为啥Android不会暂停视图完全被软键盘挡住的片段?