C# 行为古怪的幕后工作者

C# 行为古怪的幕后工作者,c#,.net,multithreading,backgroundworker,long-running-processes,C#,.net,Multithreading,Backgroundworker,Long Running Processes,我正在编写一些调用服务的代码。此服务调用可能会失败,如果失败,我希望系统重试,直到它正常工作或时间过长为止 我想知道我哪里出错了,因为下面的代码似乎工作不正常。。。它随机只做一到四个循环 protected virtual void ProcessAsync(object data, int count) { var worker = new BackgroundWorker(); worker.DoWork += (sender, e) => {

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

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

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();
}
受保护的虚拟void ProcessAsync(对象数据,整数计数)
{
var worker=新的BackgroundWorker();
worker.DoWork+=(发件人,e)=>
{
抛出新的InvalidOperationException(“哦,shiznit!”);
};
worker.RunWorkerCompleted+=(发件人,e)=>
{
//如果发生错误,我们需要告诉数据
如果(例如错误!=null)
{
计数++;
系统.线程.线程.睡眠(计数*5000);

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

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

我稍微修改了您的代码,在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);
    }
}
private void按钮1\u单击(对象发送者,事件参数e)
{
ProcessAsync(“啤酒”,1);
}
受保护的虚拟void ProcessAsync(对象数据,int计数)
{
var worker=新的BackgroundWorker();
worker.DoWork+=(发件人,e)=>
{
抛出新的InvalidOperationException(“哦,shiznit!”);
};
worker.RunWorkerCompleted+=(发件人,e)=>
{
//如果发生错误,我们需要告诉数据
如果(例如错误!=null)
{
计数++;
//系统.线程.线程.睡眠(计数*5000);

如果(count我稍微修改了您的代码,并且在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);
    }
}
private void按钮1\u单击(对象发送者,事件参数e)
{
ProcessAsync(“啤酒”,1);
}
受保护的虚拟void ProcessAsync(对象数据,int计数)
{
var worker=新的BackgroundWorker();
worker.DoWork+=(发件人,e)=>
{
抛出新的InvalidOperationException(“哦,shiznit!”);
};
worker.RunWorkerCompleted+=(发件人,e)=>
{
//如果发生错误,我们需要告诉数据
如果(例如错误!=null)
{
计数++;
//系统.线程.线程.睡眠(计数*5000);

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


我想不出为什么你不使用try/catch块循环DoWork方法。

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


我想不出有什么理由不使用try/catch块来循环DoWork方法。

有一件事非常不好

RunWorkerCompleted()
中调用
Thread.Sleep()
。由于该函数将在GUI线程中处理,因此应用程序将冻结

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

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

更新

要在给定的时间段后开始某件事,你应该看一看。每一个都有它自己的优点和缺点。要获得更深入的见解,你应该看一看。

有一件事是非常不好的。

RunWorkerCompleted()
中调用
Thread.Sleep()
。由于该函数将在GUI线程中处理,因此应用程序将冻结

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

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

更新

若要在给定的时间段后开始某项工作,您应该查看。它们每个都有各自的优点和缺点。若要查看更深入的视图,您应该查看。

它是否与
worker.RunWorkerAsync();
而不是
this.ProcessAsync(数据,计数)一起工作
?@Marc Gravell:如果是这样的话,我想他必须使用一个全局计数器。我能让这段代码像你描述的那样失败的唯一方法是将
计数从1到4(包括1)随机开始有了<代码>日志。失败< /代码>抛出一个异常。服务是一个WCF服务吗?如果你有控制权的话,那么如果考虑WCF可靠的会话。它不会与<代码> Works.RunWorksActhCy](<代码> >而不是<代码> >吗?
?@Marc Gravell:那样的话,我想,他就得用一个全局计数器了。这是我唯一能做到的