【问题标题】:BackgroundWorker acting bizarrelyBackgroundWorker 行为怪异
【发布时间】:2010-05-11 04:21:36
【问题描述】:

我正在编写一些调用服务的代码。此服务调用可能会失败,如果失败,我希望系统重试,直到它正常工作或时间过长。

我想知道我哪里出错了,因为以下代码似乎无法正常工作...它随机只执行一到四个循环...

protected virtual void ProcessAsync(object data, int count)
{
    var worker = new BackgroundWorker();
    worker.DoWork += (sender, e) =>
    {
        throw new InvalidOperationException("oh shiznit!");
    };
    worker.RunWorkerCompleted += (sender, e) =>
    {
        //If an error occurs we need to tell the data about it
        if (e.Error != null)
        {
            count++;
            System.Threading.Thread.Sleep(count * 5000);
            if (count <= 10)
            {
                if (count % 5 == 0)
                    this.Logger.Fatal("LOAD ERROR - The system can't load any data", e.Error);
                else
                    this.Logger.Error("LOAD ERROR - The system can't load any data", e.Error);
                this.ProcessAsync(data, count);
            }
        }
    };
    worker.RunWorkerAsync();
}

干杯 安东尼

更新:

我已将我的代码切换为使用 ThreadPool.QueueUserWorkItem... 自从这样做后,我的问题就消失了,并且在语义上我可以做同样的事情。感谢大家的帮助。

【问题讨论】:

  • 它不适用于worker.RunWorkerAsync(); 而不是this.ProcessAsync(data, count); 吗?
  • @Marc Gravell:在这种情况下,我认为,他将不得不使用全局计数器。
  • 我能够让 此代码 像您描述的那样失败的唯一方法是将 count 随机化为从 1 到 4(含)开始并让 @987654325 @ 抛出异常。
  • 该服务是您可以控制的 WCF 服务吗?如果是这样,请考虑 WCF 可靠会话。

标签: c# .net multithreading backgroundworker long-running-processes


【解决方案1】:

我已经稍微修改了您的代码,并且在运行 10 次迭代(VS 2008 Express)时没有任何问题,这使我想到:这是 实际 代码吗?如果不是,你是确定您已发送足够的数据来重现该问题?

如果我冒险猜测一下,我会说您发送的计数会发生变化,例如 count % 5 &gt; 0 并且在 Logger.Fatal 中抛出异常。

private void button1_Click(object sender, EventArgs e)
{
    ProcessAsync("beer", 1);
}

protected virtual void ProcessAsync(object data, int count)
{
    var worker = new BackgroundWorker();
    worker.DoWork += (sender, e) =>
    {
        throw new InvalidOperationException("oh shiznit!");
    };
    worker.RunWorkerCompleted += (sender, e) =>
    {
        //If an error occurs we need to tell the data about it
        if (e.Error != null)
        {
            count++;
            //System.Threading.Thread.Sleep(count * 5000);
            if (count <= 10)
            {
                if (count % 5 == 0)
                    this.Logger.Fatal("LOAD ERROR - The system can't load any data - " + count.ToString(), e.Error);
                else
                    this.Logger.Error("LOAD ERROR - The system can't load any data - " + count.ToString(), e.Error);
                this.ProcessAsync(data, count);
            }
        }
    };
    worker.RunWorkerAsync();
}

SomeLogger Logger = new SomeLogger();

class SomeLogger
{
    public void Fatal(string s, Exception e)
    {
        System.Diagnostics.Debug.WriteLine(s);
    }

    public void Error(string s, Exception e)
    {
        System.Diagnostics.Debug.WriteLine(s);
    }
}

编辑:建议
Logger.Fatal 的调用进行try-catch,看看会发生什么。

编辑:另一个建议
我怀疑您没有共享足够的代码让我们提供帮助。这里成功的关键是将问题隔离在一个只有足够代码来显示失败的虚拟项目中。我敢打赌,如果你能做到这一点,你很可能不需要在这里发布这个问题......

您可以从我的假设开始,应该会发现这很好用。然后开始将通用代码更改为您实际使用的代码(我将从 Logger.Fatal 的实际实现开始)。该错误可能很快就会变得非常明显。

【讨论】:

  • 我同意 - 海报的代码在 VS 2010 中使用 Console.Writeline() 调用而不是 Logger 类调用可以正常工作。我会把钱花在奥斯汀关于 Logger.Fatal() 抛出异常的想法上。
  • 当你重新进入睡眠时它是否工作......重要的是睡眠在那里,就好像最后一次调用失败它不太可能下一个将在之后工作......
  • 是的,代码确实有效。除了 Simon 已经提到的 Logger 之外,是否存在第三方依赖?
  • 它与Sleep 调用配合得很好;没有它就更容易测试。
  • 我已经尝试将 try catch 放在它周围,在抛出第 4 个异常之后,它甚至似乎都没有运行 RunWorkerCompleted...
【解决方案2】:

这一定是我见过的最离奇的重试机制了。你能做一个更干净的吗?避免递归调用,除非它们简单且易于维护,因为它很容易导致错误。

【讨论】:

  • "避免递归调用,除非它们简单且易于维护,因为它很容易导致错误。" ——这是相当笼统的概括。在这种情况我同意递归不是要走的路。但是有些问题可以通过递归更自然地解决,我不明白为什么递归比迭代更难维护。
  • 它不是递归的,ProcessAsync 在事件运行时已经退出。
【解决方案3】:

我没有看到明显的原因。但是,您的 RunWorkerCompleted 事件通常会在 UI 线程上运行。并将其挂起长达 55 秒。这是不可取的。

没有任何理由我能想到为什么您不只是在 DoWork 方法中循环使用 try/catch 块。

【讨论】:

  • 我同意。也许他可以使用单独的线程来避免 UI 挂起?!
  • 我不是那个意思。如果可以,他应该将 UI 和后台任务分开。
【解决方案4】:

有一件事真的很不好

在您的RunWorkerCompleted() 中,您调用Thread.Sleep()。由于这个事实,这个函数将在你的应用程序将冻结的 GUI 线程中处理!

请不要在 BackgroundWorker 的任何事件中调用 Thread.Sleep(),因为它们都会在 GUI 线程中处理。

因此,这可能不是您当前问题的真正解决方案,但绝对是您应该关心的事情。

更新
要在给定时间段后开始某些事情,您应该查看varioustimerclasses。他们每个人都有自己的优点和缺点。如需更深入的了解,您应该查看this article

【讨论】:

  • 是否有另一种方法可以设置进程在 x 时间段内自动重试...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-03
  • 2012-08-05
  • 2012-12-03
相关资源
最近更新 更多