C# 如果出现某些错误,请在后台重新启动任务

C# 如果出现某些错误,请在后台重新启动任务,c#,multithreading,task-parallel-library,C#,Multithreading,Task Parallel Library,我使用Mono.Mac(3.2.3)的一些REST请求与服务器通信,作为重试机制,我悄悄地尝试在HTTP操作失败或超时时进行多次尝试 我有以下几点: var tries = 0; while (tries <= ALLOWED_TRIES) { try { postTask.Start(); tries++; if (!postTask.Wait(Timeout)) { throw ne

我使用Mono.Mac(3.2.3)的一些REST请求与服务器通信,作为重试机制,我悄悄地尝试在HTTP操作失败或超时时进行多次尝试

我有以下几点:

var tries = 0;
while (tries <= ALLOWED_TRIES)
{
    try
    {
        postTask.Start();
        tries++;
        if (!postTask.Wait(Timeout))
        {
            throw new TimeoutException("Operation timed out");
        }
        break;
    } catch (Exception e) {
        if (tries > ALLOWED_TRIES)
        {
            throw new Exception("Failed to access Resource.", e);
        }
    }
}
var=0;
while(允许的尝试次数)
{
抛出新异常(“无法访问资源。”,e);
}
}
}
其中任务使用父方法的参数,如下所示

var postTask = new Task<HttpWebResponse>(() => {return someStuff(foo, bar);},
    Task.Factory.CancellationToken, 
    Task.Factory.CreationOptions);
var postTask=newtask(()=>{returnsomething(foo,bar);},
Task.Factory.CancellationToken,
任务、工厂、创作选项);

问题似乎是,任务在第一次完成(以及随后的失败)后,不希望使用
postTask.Start()
再次运行该任务。有没有一种简单的方法可以做到这一点,或者我是否以这种方式滥用了任务?是否有某种方法可以将任务重置为初始状态,或者我最好使用某种工厂?

您在这里确实误用了
任务,原因如下:

  • 同一任务不能运行多次。当它完成时,它就完成了

  • 不建议手动构造
    Task
    对象,有
    Task.Run
    Task.Factory.Start

  • 对于执行IO绑定工作的任务,不应使用
    Task.Run
    /
    Task.Factory.Start
    。它们用于CPU限制的工作,因为它们从
    ThreadPool
    中“借用”线程来执行任务操作。相反,使用基于纯异步
    任务
    的API来实现这一点,它不需要专门的线程来完成

例如,在下面,您可以从UI线程调用
GetResponseWithRetryAsync
,并保持UI响应:

async Task<HttpWebResponse> GetResponseWithRetryAsync(string url, int retries)
{
    if (retries < 0)
        throw new ArgumentOutOfRangeException();

    var request = WebRequest.Create(url);
    while (true)
    {
        try
        {
            var result = await request.GetResponseAsync();
            return (HttpWebResponse)result;
        }
        catch (Exception ex)
        {
            if (--retries == 0)
                throw; // rethrow last error
            // otherwise, log the error and retry
            Debug.Print("Retrying after error: " + ex.Message);
        }
    }
}
async任务GetResponseWithRetryAsync(字符串url,int重试)
{
如果(重试次数<0)
抛出新ArgumentOutOfRangeException();
var request=WebRequest.Create(url);
while(true)
{
尝试
{
var result=wait request.GetResponseAsync();
返回(HttpWebResponse)结果;
}
捕获(例外情况除外)
{
如果(--retries==0)
throw;//重新显示上一个错误
//否则,请记录错误并重试
Debug.Print(“错误后重试:+ex.Message”);
}
}
}
更多阅读:


.

我建议您这样做:

private int retryCount = 3;
...

public async Task OperationWithBasicRetryAsync()
{
  int currentRetry = 0;

  for (; ;)
  {
    try
    {
      // Calling external service.
      await TransientOperationAsync();

      // Return or break.
      break;
    }
    catch (Exception ex)
    {
      Trace.TraceError("Operation Exception");

      currentRetry++;

      // Check if the exception thrown was a transient exception
      // based on the logic in the error detection strategy.
      // Determine whether to retry the operation, as well as how 
      // long to wait, based on the retry strategy.
      if (currentRetry > this.retryCount || !IsTransient(ex))
      {
        // If this is not a transient error 
        // or we should not retry re-throw the exception. 
        throw;
      }
    }

    // Wait to retry the operation.
    // Consider calculating an exponential delay here and 
    // using a strategy best suited for the operation and fault.
    Await.Task.Delay();
  }
}

// Async method that wraps a call to a remote service (details not shown).
private async Task TransientOperationAsync()
{
  ...
}

此代码来自Microsoft的重试模式设计。你可以在这里查看:

这假设是C#5.0,从这个问题上我不清楚这是一个选项。@svick,同样可以通过
ContinueWith
回调来完成,尽管代码没有那么可读性。@svick,这里有一个,作为我的学习练习,我已经学会了更爱
async/await
。为了获得提示和“理论”组件,我将给出答案,但需要注意的是,扩展问题(与.NET 4兼容)中提供的答案是我衍生解决方案的来源。感谢您的努力,非常感谢。丹尼尔帕克,很高兴它起了作用。