C# BackgroundWorker 并行调用 DoWorkEventHandler

发布于 2024-11-02 11:21:00 字数 1740 浏览 1 评论 0原文

这是我的情况:
我有一个启动BackgroundWorkers的ThreadManager;我订阅 doWork 事件以在其中记录内容。我还订阅了 BackgroundWorker 本身中的 doWork 事件来处理内容。 好吧,第一个订阅在第二个订阅引发后引发事件。

class ThreadManager
{
  //(...)
  for (int i = 0; i<100; i++)
  {
   myWorker wk = new myWorker();
   wk.DoWork += new DoWorkEventHandler(wk_DoWork);
  }
  //(...)

  public void wk_DoWork(object sender, DoWorkEventArgs e)
    {
      Console.Out.Write("PONG");
      //(...) Workers Management logic (Pooling, priority, etc.)
    }
}


internal class myWorker : : BackgroundWorker
{
   //(...)
   DoWork += new DoWorkEventHandler(DoMe);
   //(...)

   void DoMe(object sender, DoWorkEventArgs e)
   {
      Console.Out.Write("PING");
      //(...) Run a 2-3mn file reading process           
   }
}

由于某种原因,我连续得到所有“Ping”,并在几分钟后开始得到“Pong”。

我在这里缺少什么吗?

编辑:
我本身不使用“控制台”,而是使用异步记录器(即示例)。我仔细观察了“PONG”行的调试过程,在“PING”启动后它就没有被命中。

我的解决方案: 这正是我希望避免的额外代码,但我最终无法消除痛苦。 所以,对于那些有相同问题并在这篇文章中绊倒的人来说:

class ThreadManager
{
  //(...)
  for (int i = 0; i<100; i++)
  {
   myWorker wk = new myWorker();
   wk.StartedEvent += new myWorker.startDelegate(wk_Started);
  }
  //(...)

  public void wk_Started(params-if-needed)
    {
      Console.Out.Write("PONG");
      //(...) Do Stuff
    }
}   

internal class myWorker : BackgroundWorker
{
   public delegate void startDelegate(string ID);
   public event startDelegate StartedEvent;

   protected override void OnDoWork(DoWorkEventArgs e)
   {
      StartedEvent(ID); //put whatever parameter suits you or nothing
      base.OnDoWork(e);
      e.Result = e.Argument;

      Console.Out.Write("PING");
      //(...) Do Stuff     
   }
}

Here is my situation :
I have a ThreadManager launching BackgroundWorkers; I subscribe to the doWork event to Log stuff in it. I also subscribo to the doWork event in the BackgroundWorker itself to process stuff.
Well, The first subscription raises the event way after the second one was raised.

class ThreadManager
{
  //(...)
  for (int i = 0; i<100; i++)
  {
   myWorker wk = new myWorker();
   wk.DoWork += new DoWorkEventHandler(wk_DoWork);
  }
  //(...)

  public void wk_DoWork(object sender, DoWorkEventArgs e)
    {
      Console.Out.Write("PONG");
      //(...) Workers Management logic (Pooling, priority, etc.)
    }
}


internal class myWorker : : BackgroundWorker
{
   //(...)
   DoWork += new DoWorkEventHandler(DoMe);
   //(...)

   void DoMe(object sender, DoWorkEventArgs e)
   {
      Console.Out.Write("PING");
      //(...) Run a 2-3mn file reading process           
   }
}

For some reason, I am getting all "Pings" in a row, and start getting Pongs only a few minutes after.

Is there something I am missing here ?

EDIT :
I do not use "Console" per se, but asynchronous loggers (that was for the example). I have been careful to watch the debug process at the "PONG" line, and it is not hit way after the "PING"s has been launched.

MY SOLUTION :
This is exactly the extra code I was hoping to avoid, but I could'nt cut the pain finally.
So here it is, for those having the same issu and stumbling on this post :

class ThreadManager
{
  //(...)
  for (int i = 0; i<100; i++)
  {
   myWorker wk = new myWorker();
   wk.StartedEvent += new myWorker.startDelegate(wk_Started);
  }
  //(...)

  public void wk_Started(params-if-needed)
    {
      Console.Out.Write("PONG");
      //(...) Do Stuff
    }
}   

internal class myWorker : BackgroundWorker
{
   public delegate void startDelegate(string ID);
   public event startDelegate StartedEvent;

   protected override void OnDoWork(DoWorkEventArgs e)
   {
      StartedEvent(ID); //put whatever parameter suits you or nothing
      base.OnDoWork(e);
      e.Result = e.Argument;

      Console.Out.Write("PING");
      //(...) Do Stuff     
   }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

信愁 2024-11-09 11:21:00

您缺少以下内容:
DoWork 事件的订阅者不是并行调用,而是以串行方式调用,即首先使用 PING 调用处理程序,然后使用 PONG 调用处理程序。因此,当 PING 处理程序需要 3 分钟时,PONG 处理程序将在您调用 RunWorkerAsync 三分钟后执行。

You are missing the following:
The subscribers to the DoWork event are not called in parallel but in a serial manner, i.e. first your handler with PING and after that the handler with PONG. So, when the PING handler takes 3 minutes, the PONG handler will be executed three minutes after you called RunWorkerAsync.

月亮是我掰弯的 2024-11-09 11:21:00

DoWork 是一个普通事件,通过多播,它是一个顺序调用链,BackgroundWorker 不会改变这一点。

简而言之,将多个事件处理程序挂起该事件的情况并不常见。

所以是的,这是非常自然的,因为您在评论中特别提到第一个事件处理程序运行 2-3 分钟,然后是的,第二个事件处理程序将在几分钟后启动。

DoWork is a normal event, and with multicast, it's a sequential call-chain, and BackgroundWorker does not change that.

In short, it's not typical to hang multiple event handlers off of that event.

So yes, it's perfectly natural, since you specifically mention in your comments that the first event handler runs for 2-3 minutes, then yes, the second event handler will start a few minutes later.

萝莉病 2024-11-09 11:21:00

据我所知,Console.Out.Write 是缓冲的。尝试WriteLine。

As far as I know, Console.Out.Write is buffered. Try WriteLine.

盛夏尉蓝 2024-11-09 11:21:00

这可能不相关,但建议重写派生类中的 OnXXX 方法,而不是订阅自己的事件。因此,

class MyWorker : BackgroundWorker
{
    protected override void OnDoWork(...) { .... }
}

不要忘记调用base.OnDoWork()

This might be unrelated, but it's recommended to override OnXXX methods in derived classes rather then subscribe to own events. Thus,

class MyWorker : BackgroundWorker
{
    protected override void OnDoWork(...) { .... }
}

And do not forget to call base.OnDoWork().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文