BackgroundWorker表现得很奇怪

时间:2010-05-11 04:21:36

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

我正在研究一些调用服务的代码。此服务调用可能会失败,如果确实如此,我希望系统再次尝试,直到它工作或经过太多时间。

我想知道我哪里出错了,因为下面的代码似乎没有正常工作......它随机只做一到四个循环......

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而不是......自从这样做以后我的问题就消失了,语义上我可以做同样的事情。谢谢你所有的帮助。

4 个答案:

答案 0 :(得分:4)

我稍微修改了你的代码并且在10次迭代(VS 2008 Express)中没有遇到任何问题,这导致我:这是实际的代码,如果没有,是你吗?你确定已经发送了足够重现的问题吗?

如果我冒昧地猜测,我会说你发送它的数量不同count % 5 > 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的调用进行试试,看看会发生什么。

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

你可以从我的假设开始,应该看到这很好用。然后开始将通用代码更改为您实际使用的内容(我将从Logger.Fatal的实际实现开始)。错误很可能在短时间内变得非常明显。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

我没有任何理由可以想到你为什么不用try / catch块循环DoWork方法。

答案 3 :(得分:0)

有一件事真的是糟糕

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

请勿在任何BackgroundWorker事件中调用{{1}},因为所有这些事件都将在GUI线程中处理。

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

<强>更新
要在给定时间段后开始播放某些内容,您应该查看various timer classes。他们每个人都有自己的优点和缺点。要获得更深入的观点,您应该查看this article