Mono的BackgroundWorker不在后台工作?

Tom*_*Tom 4 .net c# mono multithreading backgroundworker

我有Mono的困境.我试图了解BackgroundWorker实例不会同时运行的方式或原因,或者至少不能非常有效或快速地运行实例.这几乎就像线程的数量受到限制一样,但我不是Mono开发人员或.NET开发人员,所以我把自己置于我的兄弟们的怜悯之下.

请考虑以下示例:

using System;
using System.ComponentModel;
using System.Threading;

namespace backgroundworkertest
{
  class MainClass
  {
    public static void foo(object sender, DoWorkEventArgs e) {
      Console.WriteLine("Start");
      Thread.Sleep(500);
      Console.WriteLine("Done");
    }

    public static void Main (string[] args)
    {
      for(int i = 0; i < 6; i++) {
        BackgroundWorker b = new BackgroundWorker();
        b.WorkerReportsProgress = false;
        b.DoWork += new DoWorkEventHandler(foo);
        b.RunWorkerAsync();
      }

      Thread.Sleep(2000);
      Console.WriteLine("Really done");
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

当我运行上面的内容时,我得到以下输出.

Start
Start
Done
Start
Start
Done
Start
Done
Really Done

首先,并非所有的BackgroundWorkers都在两秒内完成.从循环中可以清楚地看出我正在实例化6名工人,但只有3名人员打印"完成".如果所有6个人同时运行,我觉得两秒钟应该足够让这些工人完成.

真正的内幕故事是我有一个运行良好的应用程序(使用大量的BackgroundWorkers在后台通过HTTP获取图像.但不同的是,这个应用程序是在C#.NET中实现的.当我移植应用程序时对于Mono,BackgroundWorkers似乎一次只能运行一对,并且HTTP连接很容易超时.我想看看是否是这种情况,因此上面的示例和问题......

这里发生了什么?为什么并非所有的BackgroundWorkers同时运行?我需要设置一些参数吗?

Chr*_*ens 9

我对Mono的实现并不是100%肯定,但我对微软的版本相当了解,我只能假设Mono的行为方式相同或类似.

首先,澄清一下,事实上,BackgroundWorker 它确实产生了.NET线程(与本机线程不同),它与你ThreadPool.QueueUserWorkItem自己调用一样.这是一个微小的细节,可以帮助您理解为什么您会看到这种行为.重要的是要记住.NET中的线程可能实际上并不代表本机线程.实际上,所有6个后台工作程序在运行6个.NET线程时都可以在1-2个本机线程上运行.在我的机器上,实际上只有3个本机线程使用上面的代码生成.

其次,您没有考虑构造new BackgroundWorker,设置委托,然后异步运行worker所花费的时间,这可能涉及也可能不涉及创建本机线程,这实际上是一项相当昂贵的操作.添加一个计时器,在我的测试中,总共需要一点点的时间来创建所有六个,有时候更长一点.由于调度,ThreadPool可能需要几毫秒才能发现所有线程都饱和/阻塞(因为Thread.Sleep),然后创建一个新线程.这意味着,在某些情况下,您的后台工作人员可能会在0:01:700左右开始,只剩下300毫秒,但该功能会休眠500毫秒.没有足够的时间完成任务.

我不认为Mono的实现运行速度比微软慢一点是有争议的,我确信你可能没有发现你可以在运行时发现同样的行为.

如果有疑问,请责怪自己的代码,因为这通常是问题所在.睡觉你期望手术完成的时间,并不是一个真正的测试方法.如果计算机上运行其他程序会发生什么? Thread.Sleep如果其他进程的线程已抢占你的线程,则运行速度不会变慢.在这种情况下,情况会更糟.

如果您要在foo方法中将代码更改为睡眠5毫秒,并在创建后台工作程序后在main方法中等待20毫秒,则您等待的比率相同,并且我能够看到以下内容:

Start
Start
Done
Done
Start
Start
Really done
Press any key to continue . . .

只有两个完成,甚至没有全部开始.我希望你现在看到测试中的缺陷.它们同时运行,我猜你的问题可能在其他地方.你说你在后台通过http获取图像.请记住,如果某些东西不能正常工作,我会说只有1%的时间实际上有一些时髦的运行时间,另外99%的时间是你的代码.您使用的是同步还是异步I/O?只有一个线程处理请求?我从那里开始.

编辑:

我决定看看Mono中的性能是什么样的,而不仅仅依赖于我在Microsoft实现中发现的内容.在发现Mono实际上正在开始所有6个背景作品之后; 它们都在2000ms的范围内完成!为了记录,这里是结果的比较.我稍微修改了代码以显示正在发生的事情,但我向你保证,当我按原样运行你的代码时,我得到了相同的结果.在主线程进入2000ms睡眠之前打印"完成创建..."消息,其中打印的时间戳是后台工作人员输入其工作方法的时刻.

Windows                      Mono
Done Creating...             Done Creating...
00:00:00.0018610             00:00:00.0088775
00:00:00.0019544             Start
Start                        00:00:00.5074494
Start                        Start
Done                         Done
Done                         00:00:00.5615083
00:00:00.5027995             Start
Start                        Done
00:00:00.5028008             00:00:01.0082133
Start                        Start
Done                         00:00:01.0082900
Done                         Start
00:00:01.0025428             Done
Start                        00:00:01.0618140
00:00:01.0026164             Start
Start                        Done
Done                         Done
Done                         Done
Really done                  Really done

我在完全相同的两个盒子上运行测试(戴尔T3400,相同的硬件),一个是Windows 7 x64,另一个是Ubuntu 12.04 x64.没有不同.确保您使用可执行文件的发布版本对此进行测试,而不附加任何调试程序.还要确保您在相同的硬件上进行测试.你的linux/mono安装问题是可能的,但不太可能,这是一个问题(假设你在linux上运行mono,而不是windows).就像我之前说过的那样,我认为这些结果支持它,我不认为这是问题所在.我会在你的代码中的某个地方寻找其他地方.