栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如果任务异常,则根据用户输入多次重试任务

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如果任务异常,则根据用户输入多次重试任务

更新5/2017

C#6 异常过滤器使

catch
子句更加简单:

    private static async Task<T> Retry<T>(Func<T> func, int retryCount)    {        while (true)        { try {     var result = await Task.Run(func);     return result; } catch when (retryCount-- > 0){}        }    }

和递归版本:

    private static async Task<T> Retry<T>(Func<T> func, int retryCount)    {        try        { var result = await Task.Run(func); return result;        }        catch when (retryCount-- > 0){}        return await Retry(func, retryCount);    }

原版的

编码Retry函数的方法有很多种:您可以使用递归或任务迭代。一段时间以来,希腊.NET用户组中进行了讨论,讨论了执行此操作的不同方法。
如果使用的是F#,则还可以使用异步构造。不幸的是,您至少不能在异步CTP中使用async /
await构造,因为编译器生成的代码不喜欢多次等待或在catch块中重新抛出。

递归版本可能是在C#中构建Retry的最简单方法。以下版本不使用Unwrap,而是在重试之前添加了可选的延迟:

private static Task<T> Retry<T>(Func<T> func, int retryCount, int delay, TaskCompletionSource<T> tcs = null)    {        if (tcs == null) tcs = new TaskCompletionSource<T>();        Task.Factory.StartNew(func).ContinueWith(_original =>        { if (_original.IsFaulted) {     if (retryCount == 0)         tcs.SetException(_original.Exception.InnerExceptions);     else         Task.Factory.StartNewDelayed(delay).ContinueWith(t =>         {  Retry(func, retryCount - 1, delay,tcs);         }); } else     tcs.SetResult(_original.Result);        });        return tcs.Task;    }

所述StartNewDelayed函数来自ParallelExtensionsExtras样品和使用定时器发生超时时,以触发TaskCompletionSource。

F#版本要简单得多:

let retry (asyncComputation : Async<'T>) (retryCount : int) : Async<'T> = let rec retry' retryCount =     async {        try let! result = asyncComputation   return result        with exn -> if retryCount = 0 then     return raise exn else     return! retry' (retryCount - 1)    }retry' retryCount

不幸的是,不可能从Async CTP使用async /
await在C#中写类似的东西,因为编译器不喜欢catch块中的await语句。以下尝试也无法静默失败,因为运行时不喜欢在异常后遇到等待:

private static async Task<T> Retry<T>(Func<T> func, int retryCount)    {        while (true)        { try {     var result = await TaskEx.Run(func);     return result; } catch  {     if (retryCount == 0)         throw;     retryCount--; }        }    }

至于询问用户,您可以修改重试以调用询问用户并通过TaskCompletionSource返回任务的函数,以在用户回答时触发下一步,例如:

 private static Task<bool> AskUser()    {        var tcs = new TaskCompletionSource<bool>();        Task.Factory.StartNew(() =>        { Console.WriteLine(@"Error Occured, continue? YN"); var response = Console.ReadKey(); tcs.SetResult(response.KeyChar=='y');        });        return tcs.Task;    }    private static Task<T> RetryAsk<T>(Func<T> func, int retryCount,  TaskCompletionSource<T> tcs = null)    {        if (tcs == null) tcs = new TaskCompletionSource<T>();        Task.Factory.StartNew(func).ContinueWith(_original =>        { if (_original.IsFaulted) {     if (retryCount == 0)         tcs.SetException(_original.Exception.InnerExceptions);     else         AskUser().ContinueWith(t =>         {  if (t.Result)      RetryAsk(func, retryCount - 1, tcs);         }); } else     tcs.SetResult(_original.Result);        });        return tcs.Task;    }

通过所有后续操作,您可以了解为什么非常需要异步版本的Retry。

更新:

在Visual Studio 2012 Beta中,以下两个版本适用:

一个带有while循环的版本:

    private static async Task<T> Retry<T>(Func<T> func, int retryCount)    {        while (true)        { try {     var result = await Task.Run(func);     return result; } catch {     if (retryCount == 0)         throw;     retryCount--; }        }    }

和递归版本:

    private static async Task<T> Retry<T>(Func<T> func, int retryCount)    {        try        { var result = await Task.Run(func); return result;        }        catch        { if (retryCount == 0)     throw;        }        return await Retry(func, --retryCount);    }


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/411865.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号