【问题标题】:C# BackgroundWorker Cancellation checkpoint shorteningC# BackgroundWorker 取消检查点缩短
【发布时间】:2011-08-03 22:57:56
【问题描述】:

有没有办法缩短我的BackgroundWorker.CancellationPending检查点?

例如,有没有办法像下面的示例代码一样封装return?:

//REAL CODE (CURRENTLY USE THIS)
if (this.TW.CancellationPending) 
    return; 

//PSEUDO REPLACEMENT CODE
this.CkPt(CurrentMethod); //PSEUDO USAGE 
    //^^^ PARAMETER IS A REFERENCE TO THE CURRENT METHOD, SIMILAR TO `this` FOR AN OBJECT  
//OR MAYBE AN EXTENSION METHOD WOULD LOOK CLEANER
CurrentMethod.CkPt(); //PSEUDO USAGE

private void CkPt(Method m) //PSEUDO METHOD
{
    /*
        POSSIBLY PERFORM OTHER CHECKPOINT TASKS HERE
    */
    if (this.TW.CancellationPending) 
        m.return/*FROM METHOD THAT CALLED ME*/;
}  

我正在尝试使这样的多检查点情况更具可读性:

//PSUEDO METHOD 
//DO NOT TAKE THIS AS REPEATING CODE
//IT IS ONLY MEANT TO SHOW MULTIPLE USES OF THE SAME CHECKPOINT
//MY REAL TASK METHOD(S) CONTAIN MANY MANY MANY AREAS THAT DON'T REPEAT AND REQUIRE CHECKPOINTS  
public void FakeBWTask()
{
    if (this.TW.CancellationPending) 
        return; 

    foreach (var F1 in Fake1)
    {
        if (this.TW.CancellationPending) 
            return; 

        foreach (var F2 in Fake2)
        {   
            if (this.TW.CancellationPending) 
                return; 
            foreach (var F3 in Fake3)
            {
                if (this.TW.CancellationPending) 
                    return; 
            }
        }
    }
}

感谢您的帮助!!

【问题讨论】:

  • 嗯,当然是笨拙的代码。将异常注入线程是每个人最喜欢的 bugaboo。线程取消在小于人类感知时间的任何时间都有效是否真的重要? 50 毫秒是一个 hellofalot 的 CPU 周期。
  • 是为了阻止事件的发生,只是一个例子。在我的真实代码中,事件比 50 毫秒长得多。我真的不应该把第二个代码放在那里。它破坏了这个问题。

标签: c# backgroundworker return checkpoint


【解决方案1】:

没有办法让methodA调用methodB,让methodB返回methodA(因为我们没有尾递归)

考虑使用这样的迭代器。它适用于某些情况下,您可以将 try/catch 置于检查点之间。

public void FakeBWTask()
{
   if (this.TW.CancellationPending) 
      return; 
   foreach (object ignore in FakeBWTaskSteps())
   {
      // Other checkpoint logic here....
      if (this.TW.CancellationPending) 
          return; 
   }
}

private IEnumerable<object> FakeBWTaskSteps()
{
   Part1();
   yield return null; // Execute checkpoint logic.

   Part2();
   yield return null; // Execute checkpoint logic.

   Part3();
   yield return null; // Execute checkpoint logic.

   Part4();
   yield return null; // Execute checkpoint logic.

   // Do some other stuff.
   yield return null; // Execute checkpoint logic.

   // final stuff.  No looping here.
}

【讨论】:

  • 对不起,在我的示例代码中不清楚。我只是很快写了一些重复的代码,这些代码并不打算被视为重复。遍历它不是我想要的,也没有回答我的问题。我的 REAL 代码根本不重复,并且包含多个检查点。我将更新上面的示例。
  • @PiZzL3,如果检查点逻辑每次都相同,这将起作用。如果检查点逻辑不同,则返回一个可以执行该逻辑的委托。
  • @PiZzLe3,我已经更新了我的答案,但我仍然不明白为什么它错过了标记。
  • 检查点逻辑是一样的(if (this.TW.CancellationPending) return;),但它周围的代码不是。没有重复。所以我根本不明白这将如何工作。我正在寻找一种方法将return 语句封装在一个方法中,并让它在满足条件时从调用方法中调用return
  • 既然没有办法让methodA调用methodB并让methodB返回methodA(因为我们没有尾递归),你可以考虑我的解决方案。 FakeBWTaskSteps 在每个检查点有效地返回,但 FaskeBWTask 方法会从中断的地方恢复 FakeBWTaskSteps,除非取消处于挂起状态。在调试器中单步执行它,它会很清楚。
【解决方案2】:

您可以使用 mono.Cecil 进行 IL 重写。您可以使用“可取消”属性装饰方法,然后使用该属性重写任何方法。您需要从指令流构建 CFG,编写一些代码来计算堆栈深度,识别堆栈深度为零的位置,注入节点以执行取消检查,然后将 CFG 重新序列化为方法体。可能需要大约一周的时间,再加上测试所有内容的时间。您还必须添加一个后期构建步骤。

一般来说,除非你有很多可取消的方法,否则它可能不值得。

【讨论】:

  • 哇,我见过类似的很酷的东西(使用 IL 代码的技巧),但现在我已经想不通了。我刚刚开始了解更高级的 C# 功能。
猜你喜欢
  • 1970-01-01
  • 2018-03-18
  • 2015-01-21
  • 1970-01-01
  • 2011-05-11
  • 2023-04-09
  • 2011-03-14
  • 2015-04-17
  • 2020-05-12
相关资源
最近更新 更多