.net2.0实现多线程

 简介

多线程总是那么让人振奋。大家都希望能够同时处理很多事情,不过如果我们没有正确的硬件的话,我们很难达到这点。到目前为止,我们所做的只是分开CPU使用较多的工作,使其为后台进程,这样可以使得界面上不被阻塞。

不过我希望能够得到更好的效果,并充分利用当前最新的多CPU效能。因此,我将写一个真正的多线程实例,将会有多个线程作为后台线程在运行。

这就是这篇文章将要写的,不得不说的是,最终的结果实在是让我很激动。希望你也能够发觉它的用处。
在有4个CPU的多CPU服务器上,我得到了280%的效果(测试的是CPU型的任务),在一些非CPU占用较多的任务中,它可以提高到500% 到1000%的性能。

背景

网上也有不少介绍.Net 2.0下的多线程的文章,应该说,我从它们中受益颇多。我正在使用的是BackgroundWorker .Net 2.0组件(不过也有实现在.net 1.1下的代码)。

这里,我列出一些有用的文章链接:
来自Paul Kimmel的很好的介绍性文章 http://www.informit.com/articles/article.asp?p=459619&seqNum=5&rl=1
来自Juval Löwy的介绍性文章 http://www.devx.com/codemag/Article/20639/1954?pf=true
(必看)Joseph Albahari的C#中使用线程 http://www.albahari.com/threading/part3.html
Michael Weinhardt写的在Windows Forms 2.0中一个简单安全的多线程,我使用了这个网页中的CPU密集型任务,这是他从Chris Sell的文章中引用的。
http://www.mikedub.net/mikeDubSamples/SafeReallySimpleMultithreadingInWindowsForms20/SafeReallySimpleMultithreadingInWindowsForms20.htm
如果你对多线程世界仍然不是特别熟悉或者希望了解最新的.Net 2.0的 BackgroundWorker组件,那么应该好好读读上面的文章。

提出的问题

任何一个任务……无论是CPU密集型还是普通的任务:

CPU密集型:它可以分成一个、两个或多个线程,每个线程会占用一个CPU(这样就使得程序的性能翻番)

普通任务:每一个顺序执行的普通任务,在进行数据存储或使用一个web service的时候都会有一些延迟。所有的这些,都意味着这些没有使用的时间对于用户或任务本身来说有了浪费。这些时间将被重新安排,并将被并行的任务使用,不会再丢失。也就是说,如果有100个100ms延迟的任务,它们在单线程模型和20个线程模型的性能差距会达到1000%。

我们说,如果要处理一个创建一个网站多个块的任务,不是顺序的执行,而是花1-4秒钟把所有的section创建好;商标,在线用户,最新文章,投票工具 等等…… 如果我们能够异步地创建它们,然后在发送给用户,会怎么样?我们就会节省很多webservice的调用,数据库的调用,许多宝贵的时间……这些调用会更 快地执行。看上去是不是很诱人?

解决方案如下:

调用BackgroundWorker,正如我们想要的那样,我们会继承它。后台worker会帮助我们建立一个“Worker”,用于异步地做一个工作。

我们想做的是建立一个工厂Factory(只是为了面向对象的设计,于设计模式无关),任务会放在在这个Factory中执行。这意味着,我们将有一类的任务,一些进程,一些知道如何执行任务的worker。

当然我们需要一个负责分配任务给这些worker的manager,告诉这些worker当它们做完一步或全部时,做什么事情。当然,我们也需要manager能够告诉worker停止当前的任务。它们也需要休息啊:)当manager说停止的时候,它们就应该停止。
我们将会从底至上地解释这些,首先从Worker说起,然后再继续Manager。

Worker

它是Background worker的继承类,我们构建一个构造函数,并分配两个BackgroundWorker的属性,分别是WorkerReportsProgress 和WorkerSupportsCancellation,它们的功能就向其名字的意义一样:报告进度,停止任务。每个Worker还有一个id,Manager将会通过这个id控制它们。

public class MTWorker : BackgroundWorker
   {
      #region Private members
      private int _idxLWorker = 0;
      #endregion

      #region Properties
      public int IdxLWorker
      {
         get { return _idxLWorker; }
         set { _idxLWorker = value; }
      }
      #endregion

      #region Constructor
      public MTWorker()
      {
         WorkerReportsProgress = true;
         WorkerSupportsCancellation = true;
      }
      public MTWorker(int idxWorker)
         : this()
      {
         _idxLWorker = idxWorker;
      }
      #endregion
另外,我们将重载BackgroundWorker的一些函数。事实上,最有意思的是,究竟谁在做真正的工作?它就是OnDoWork,当我们invoke或者启动多线程的时候,它就会被调用。在这里,我们启动任务、执行任务、取消和完成这个任务。
我加了两个可能的任务,一个是普通型的,它会申请并等待文件系统、网络、数据库或Webservices的调用。另一个是CPU密集型的任务:计算PI值。你可以试试增加或减少线程数量后,增加或是减少的延迟(我的意思是增减Worker的数量)

OnDoWork方法的代码

protected override void OnDoWork(DoWorkEventArgs e)

{

   //Here we receive the necessary data for doing the work...

   //we get an int but it could be a struct, class, whatever..

   int digits = (int)e.Argument;

   double tmpProgress = 0;

   int Progress = 0;

   String pi = "3";



   // This method will run on a thread other than the UI thread.

   // Be sure not to manipulate any Windows Forms controls created

   // on the UI thread from this method.

   this.ReportProgress(0, pi);

   //Here we tell the manager that we start the job..



   Boolean bJobFinished = false;

   int percentCompleteCalc = 0;

   String TypeOfProcess = "NORMAL"; //Change to "PI" for a cpu intensive task

   //Initialize calculations

   while (!bJobFinished)

   {

      if (TypeOfProcess == "NORMAL")

      {

         #region Normal Process simulation, putting a time

                 delay to emulate a wait-for-something

         while (!bJobFinished)

         {

            if (CancellationPending)

            {

               e.Cancel = true;

               return; //break

            }

            //Perform another calculation step

            Thread.Sleep(250);

            percentCompleteCalc = percentCompleteCalc + 10;

            if (percentCompleteCalc >= 100)

               bJobFinished = true;

            else

               ReportProgress(percentCompleteCalc, pi);

         }

         #endregion

      }

      else

      {

         #region Pi Calculation - CPU intensive job,

                  beware of it if not using threading ;) !!

         //PI Calculation

         if (digits > 0)

         {

            pi += ".";

            for (int i = 0; i < digits; i += 9)

            {

               // Work out pi. Scientific bit :-)

               int nineDigits = NineDigitsOfPi.StartingAt(i + 1);

               int digitCount = System.Math.Min(digits - i, 9);

               string ds = System.String.Format("{0:D9}", nineDigits);

               pi += ds.Substring(0, digitCount);



               // Show progress

               tmpProgress = (i + digitCount);

               tmpProgress = (tmpProgress / digits);

               tmpProgress = tmpProgress * 100;

               Progress = Convert.ToInt32(tmpProgress);

               ReportProgress(Progress, pi);

               // Deal with possible cancellation

               if (CancellationPending) //If the manager says to stop, do so..

               {

                  bJobFinished = true;

                  e.Cancel = true;

                  return;

               }

            }

         }

         bJobFinished = true;

         #endregion

      }



   }

   ReportProgress(100, pi); //Last job report to the manager ;)

   e.Result = pi; //Here we pass the final result of the Job

}

Manager

这是一个很有趣的地方,我确信它有很大的改进空间-欢迎任何的评论和改进!它所做的是给每个线程生成和配置一个Worker,然后给这些 Worker安排任务。目前,传给Worker的参数是数字,但是它能够传送一个包含任务定义的类或结构。一个可能的改进是选择如何做这些内部工作的策略模式。

调用InitManager方法配置任务,和它的数量等属性。然后,创建一个多线程Worker的数组,配置它们。
配置的代码如下:

private void ConfigureWorker(MTWorker MTW)

{

//We associate the events of the worker

MTW.ProgressChanged += MTWorker_ProgressChanged;

MTW.RunWorkerCompleted += MTWorker_RunWorkerCompleted;

}


Like this, the Worker’s subclassed thread management Methods are linked to the Methods held by the Manager. Note that with a Strategy pattern implemented we could assign these to the proper manager for these methods.
最主要的方法是AssignWorkers,它会检查所有的Worker,如果发现没有任务的Worker,就分配一个任务给它。直到扫描一遍之后,没有发现任何有任务的Worker,这样就意味这任务结束了。不需要再做别的了!

代码如下:

public void AssignWorkers()

{

   Boolean ThereAreWorkersWorking = false;

   //We check all workers that are not doing a job... and assign a new one

   foreach (MTWorker W in _arrLWorker)

   {

      if (W.IsBusy == false)

      {

         //If there are still jobs to be done...

         //we assign the job to the free worker

         if (_iNumJobs > _LastSentThread)

         {

          //We control the threads associated to a worker

          //(not meaning the jobs done) just 4 control.

          _LastSentThread = _LastSentThread + 1;

          W.JobId = _LastSentThread; //We assign the job number..

          W.RunWorkerAsync(_iPiNumbers); //We pass the parameters for the job.

          ThereAreWorkersWorking = true;

          //We have at least this worker we just assigned the job working..

         }

      }

      else

      {

         ThereAreWorkersWorking = true;

      }

   }



   if (ThereAreWorkersWorking == false)

   {

      //This means that no worker is working and no job has been assigned.

      //this means that the full package of jobs has finished

      //We could do something here...

      Button BtnStart = (Button)FormManager.Controls["btnStart"];

      Button BtnCancel = (Button)FormManager.Controls["btnCancel"];

      BtnStart.Enabled = true;

      BtnCancel.Enabled = false;

      MessageBox.Show("Hi, I'm the manager to the boss (user): " +

                      "All Jobs have finished, boss!!");

   }

}


只要有任务完成,这个方法就会被调用。从而,保证所有的任务能够完成。

我们还通过一个属性链接到Form上,这样我们就能向UI上输出我们想要的任何消息了。当然,你可能想链接到其它的一些类,不过这是最基本最通用的。

Well… improving it we could get a BackgroundManager for all our application needs..


界面

连接到界面上,并不是最主要的功能。这一部分的代码量非常少,也很简单:在Manager中添加一个引用,并在form的构造函数中配置它。
在一个按钮中,执行Manager类的LaunchManagedProcess方法。

private MTManager LM;

public Form1()

{

   InitializeComponent();

   LM = new MTManager(this, 25);

   LM.InitManager();

}



private void btnStart_Click(object sender, EventArgs e)

{

   btnStart.Enabled = false;

   btnCancel.Enabled = true;

   LM.LaunchManagedProcess();

}



private void btnCancel_Click(object sender, EventArgs e)

{

   LM.StopManagedProcess();

   btnCancel.Enabled = false;

   btnStart.Enabled = true;

}

原文地址:http://www.codeproject.com/KB/threads/RealMultiThreading.aspx

源码下载:http://www.codeproject.com/KB/threads/RealMultiThreading/RealMultiThreading_src.zip

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Microsoft .NET Framework 2.是微软公司开发的一个软件框架,用于支持Windows操作系统上的应用程序开发。它包含了一系列的类库和运行时环境,可以帮助开发人员更快速、更方便地开发出高质量的应用程序。同时,它还提供了一些重要的功能,如安全性、可靠性、性能优化等,可以帮助应用程序更好地运行和维护。 ### 回答2: Microsoft .NET Framework 2.0 是微软推出的一个软件开发平台,它提供了许多开发工具和库,用于开发和部署各种类型的应用程序。它是基于微软的.NET技术基础设施构建的,并且是其前身.NET Framework 1.0和1.1的升级版本。 .NET Framework 2.0引入了许多新的功能和增强功能,以提高应用程序的性能和可靠性。其中最显著的改进是引入了支持64位处理器的托管代码执行。这意味着开发人员可以利用更大的内存和更快的计算速度。 此外,.NET Framework 2.0还引入了一系列新的数据访问技术,以简化开发过程。它包括对ADO.NET的增强,以便更轻松地与数据库交互。同时,还引入了新的XML语言集成功能,在处理和操作XML数据时更加便捷。 除此之外,.NET Framework 2.0还引入了对Windows Presentation Foundation(WPF)和Windows Communication Foundation(WCF)的支持。WPF是用于创建丰富和交互式用户界面的技术,而WCF则提供了一种简化创建分布式应用程序的方法。 总的来说,.NET Framework 2.0是一个强大的开发平台,可以帮助开发人员更轻松地构建高性能和可靠的应用程序。其提供的新功能和增强功能使开发过程更加简化和高效。 ### 回答3: Microsoft .NET Framework 2.0 是由微软开发的一个软件平台,用于构建、部署和运行各种类型的应用程序。它是.NET Framework 的一个重要版本,于2005年推出。 .NET Framework 2.0 提供了一个统一的开发环境,使开发者能够使用多种编程语言(如C#、VB.NET等)来构建应用程序。它具有许多强大的功能,例如内存管理、异常处理、多线程支持等,以及许多现代编程语言中常见的特性,如面向对象编程和事件驱动编程。 .NET Framework 2.0 还引入了许多新的功能和改进。其中包括对64位操作系统的更好支持,增强的安全性功能,支持ASP.NET 2.0Web开发框架和Windows Presentation Foundation (WPF) 等用户界面技术,以及对XML Web服务和数据访问技术的改进。 使用.NET Framework 2.0,开发人员可以快速构建强大的应用程序,同时还能够充分利用操作系统的资源和功能。它提供了大量的类库和工具,使开发人员能够轻松地处理各种任务,如文件操作、数据库访问、网络通信等。 总之,Microsoft .NET Framework 2.0 是一个功能强大的软件平台,为开发者提供了丰富的工具和环境,使他们能够构建各种类型的应用程序,并充分发挥操作系统的功能和资源。它在许多领域中得到了广泛应用,成为了现代软件开发的重要基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值