一起谈.NET技术,.NET多线程的探讨

  本文开始总结.NET下的多种多线程机制,不断更新中,往各位补充。

  Invoke机制

  最近在实验一个webservice时候,想到了要用异步机制,于是好好研究了一下多线程和Invoke机制,这里写点小小的心得,如有不妥,请各位指教。

  我们往往会遇到这样的需求:有一个十分耗时间的工作(比如一个WebSerive的请求),我们不希望它阻塞现有的UI线程(因为这样会导致界面假死),而是希望它在另外一个线程里面执行,并在执行完毕之后将结果“通知”UI线程。这个需求需要通过Invoke和委托机制实现。

  参考资料:

http://www.cnblogs.com/c2303191/articles/826571.html

http://www.cnblogs.com/yuxuanji/archive/2009/07/09/1519605.html

  Invoke

  Invoke总是和委托同时使用,假设有如下代码片段:


Control.Invoke(myDelegate);

  为了解释Invoke的真正意义,首先要说明几个关于这段代码的假设:

  1.假设这段代码是在一个非UI线程中调用的,设为线程2

  2.假设Control是个控件,并且是在UI线程中创建的,设为线程1,我们在这个线程2中已设法获得了一个Control的引用;

  3.假设myDelegate是一个委托实例,无论它所指向的函数(设为函数1)在哪个类中定义;

  于是这段代码的意义是:在线程2中,将函数1放到线程1中执行!

  Invoke就这么简单!

  控件操作规则:

  在.NET中有一个规定:任何对控件的操作,都必须在创建这个控件的线程中执行,否则无效!这条规定正是Control.Invoke出现的原因,Control.Invoke相当于强制将某个函数过程放到控件所在线程中执行。还有一点十分重要:对象的方法在哪个线程中执行跟这个对象在哪个线程中创建无关。简单例子就是你在窗体类里面写的函数不一定在UI线程中执行(这一点也是我一直以来的困惑),假设,我在另外一个线程中调用了这个方法(即使是通过委托调用),这个方法仍然在另一个线程中执行。

  一个具体的例子:

  1.创建一个WinForm应该程序,在界面上放一个按钮,我的目的是在按下按钮后创建一个耗时间的线程,并执行,同时防止界面假死;

  2.创建一个类,这个类负责开启一个新的线程并执行一个长时间的操作:


public class SecondThread
{
//这个函数在UI线程中执行
public void DoProcess()
{
Thread thread = new Thread(new ThreadStart(DoTrueProcess));
thread.Start();
}

//这个函数在新的线程中执行
private void DoTrueProcess()
{
Thread.Sleep(5000);
}
}

  3.在按钮事件处理函数中启动新线程:


private void button1_Click(object sender, EventArgs e)
{
SecondThread st = new SecondThread();
//启动新操作
st.DoProcess();
}

  到这里只是实现了一个普通的多线程编程,还没有涉及如何更新UI界面的问题,我们继续:

  4.在界面中添加一个列表框,用来显示数据;

  5.由于我们需要将数据通过委托的方式在线程之间传递,于是,定义一个委托,这个委托传入一个list对象:


public delegate void NotifyUI(List<string> data);

  6.这个委托通知是SecondThread发出的,所以在SecondThread类中定义一个共有的委托对象,并调用这个对象:


public NotifyUI myDelegate;
//这个函数在新的线程中执行
private void DoTrueProcess()
{
Thread.Sleep(5000);
List<string> rdata = new List<string>() { "string1", "string2", "string3" };
if (myDelegate != null)
{
myDelegate(rdata);
}
}

  7.在form中添加一个方法适应这个委托签名,并将SecondThread实例的委托对象指向这个方法:


private void button1_Click(object sender, EventArgs e)
{
SecondThread st = new SecondThread();
st.myDelegate += new NotifyUI(NotifyReceiver);
//启动新操作
st.DoProcess();
}

private void NotifyReceiver(List<string> data)
{
listBox1.DataSource = data;
}

  如果到现在你觉得listbox能够显示data的数据,那么再次考虑:对象的方法在哪个线程中执行跟这个对象在哪个线程中创建无关myDelegate(rdata);这个调用是在新的线程中执行的,尽管指向的方法是在Form中定义的方法,但是这两者没有任何关系,此时的NotifyReceiver方法是在新线程中执行的,而这个线程不是创建listbox的线程,因此,这里对listbox的数据绑定不能成功实施。那么如何将这个NotifyReceiver封送到UI线程中执行呢?答案便是使用Invoke。

  8.把DoTrueProcess修改为如下代码:


private void DoTrueProcess()
{
Thread.Sleep(5000);
List<string> rdata = new List<string>() { "string1", "string2", "string3" };
if (myDelegate != null)
{
//获取myDelegate的目标对象,这里将是Form1的实例
Control control = myDelegate.Target as Control;
//如果目标对象是个Control的话
if (control != null)
{
//通过调用form的invoke,把委托指向的函数NotifyReceiver送到UI线程上执行
control.Invoke(myDelegate, rdata);
}
//如果目标对象不是Control,则直接执行委托
else
{
myDelegate(rdata);
}
}
}

  再次测试会发现,5秒后列表会更新,并且在这个5秒内,界面没有假死。在这个例子中我们把创建第二个线程和委托封锁都放到了SecondThread类里面,对于消费者(界面类),可以简单的通过类似事件的机制异步的处理,而不阻塞UI线程。

  BeginInvoke

  接下来,我们来看看BeginInvoke。BeginInvoke跟Invoke的唯一差别是:对于调用Invoke的线程,在Invoke的方法返回前,这个线程会阻塞;对于调用BeginInvoke的线程,在BeginInvoke的方法返回前,这个线程不会阻塞! 

  BackgroundWorker组件

  本节参考资料:BackgroundWorker类

  BackgroundWorker类允许你在单独的专用线程上运行操作。耗时的操作可以利用这个组件方便的调用。这个组件还提供了进程报告的机制。可以在Toolbox中选择该组件拖入设计器,也可以在代码中自行创建。使用这个组件相比使用Invoke要方便的多。

  这个类不复杂,下面这个图很好的说明了如何使用:

时间: 2024-07-30 01:16:25

一起谈.NET技术,.NET多线程的探讨的相关文章

浅谈java中异步多线程超时导致的服务异常_java

在项目中为了提高大并发量时的性能稳定性,经常会使用到线程池来做多线程异步操作,多线程有2种,一种是实现runnable接口,这种没有返回值,一种是实现Callable接口,这种有返回值. 当其中一个线程超时的时候,理论上应该不 影响其他线程的执行结果,但是在项目中出现的问题表明一个线程阻塞,其他线程返回的接口都为空.其实是个很简单的问题,但是由于第一次碰到,还是想了一些时间的.很简单,就是因为阻塞的那个线 程没有释放,并发量一大,线程池数量就满了,所以其他线程都处于等待状态. 附上一段自己写的调

技术与工具的探讨

  最近一直在思考技术与工具之间的关系.在谈及这个话题之间,我先来讲一个例子.   在一个武侠小说里,一个小孩父母被仇人所杀害.这个小孩立志要为父母血仇.于是,不远千辛万苦找一到一个世外高人,求高人传授其绝世武功.那么这位世外高人有两条不同的方式教育这个小孩. 方式一:放眼当今武林,最厉害的神器非屠龙刀莫属,凭自己的身手,夺得屠龙刀乃囊中取物,信手拈来.于是,轻松得到屠龙刀之后,然后对小孩体质.骨骼进行分析,再自创立一套路适合小孩体质的屠龙刀法.以屠龙刀最大的维利来配合小孩的体制,以便让小孩与屠

《创业家》牛文文:少谈点模式多谈点技术

"模式"如同当年的"主义",流行于各种创业大赛.创业励志节目.论坛的"街头"式秀场 文/创业家 牛文文 "美国某某公司你知道吧?就是刚被戴尔.惠普.思科十几亿美元抢购的那家.我们的模式和它的一样,现在还没赢利,可将来起码有十几亿人民币的市值." "我开了小煤矿,但煤运不出去,上商学院之后受到启发,想搞模式创新,具体讲就是想在铁路边上搞个煤炭物流开发区,建一个大的物流和信息流平台,把分散的煤炭集中在我这个园区,这样和铁

一起谈.NET技术,.NET 4 并行(多核)编程系列之一入门介绍

本系列文章将会对.NET 4中的并行编程技术(也称之为多核编程技术)以及应用作全面的介绍. 本篇文章的议题如下: 1. 并行编程和多线程编程的区别. 2. 并行编程技术的利弊 3. 何时采用并行编程 1.并行编程和多线程编程的区别. 1.1并行编程. 现在随着多核计算机的普及,并行编程技术,也就是多核编程技术也逐渐称为开发的主流.为此,在.NET 4 中就引入了"并行编程".在.NET 4 中一些列的Library和类为并行编程提供了支持,如: Task Parallel Librar

一起谈.NET技术,.NET缓存机制探讨与比对

相信大多数开发人员都比较了解缓存了,很多开发人员都在软件开发中使用了预定义或自定义的缓存,并从中获得了预期的应用程序的性能提升.这篇和后续文章将详细的介绍与探讨.net体系下的缓存实现的机制,并讨论它的优点与缺点. .NET缓存机制:使用缓存的实际价值 在kevinhoffman,lonnykruger的书中写到:开发人员经常需要将数据(临时数据)临时存放到一个存储媒体以便快速访问.这种临时数据的存储器叫做缓存.如果开发人员合理使用缓存,则可以大幅度提高应用程序的性能. 上面是一段完美的关于缓存

一起谈.NET技术,Silverlight的多线程能力(上)

对于多线程其实一直以来都存在很多误区:比如多任务与多线程就很容易被混为一谈,而多线程也常被理所应当的认为是并行等等.而事实却是:多任务≠多线程.单任务≠单线程.多线程不一定并行,多线程与性能不成线性关系等等,其中道理在这里不再详述.笔者认为Silverlight多线程主要作用不是在于提高性能,而是在于用户体验,其根本目的是解决用户体验中的响应速度,减少单线程带来的阻塞问题.用一个贴切的例子来形容单线程和多线程的区别:单线程就好像只有一个服务窗口卖票的车站,人们排队买票时都是单线程处理的,而且不能

一起谈.NET技术,用C#实现HTTP协议下的多线程文件传输

很多人都有过使用网络蚂蚁或网络快车软件下载互联网文件的经历,这些软件的使用可以大大加速互联网上文件的传输速度,减少文件传输的时间.这些软件为什么有如此大的魔力呢?其主要原因是这些软件都采用了多线程下载和断点续传技术.如果我们自己来编写一个类似这样的程序,也能够快速的在互联网上下载文件,那一定是非常愉快的事情.下面我就讲一讲如何利用C#语言编写一个支持多线程下载文件的程序,你会看到利用C#语言编写网络应程序是多么的容易,从中也能体会到C#语言中强大的网络功能. 首先介绍一下HTTP协议,HTTP亦

一起谈.NET技术,Silverlight 的多线程能力(下)

上一期笔者介绍了Silverlight实现多线程的诸多解决方案,本期笔者将通过一个实例来实现所有多线程编程方法,并且还将于JavaScript和Flash两种Web客户端技术性能进行比较,请勿拍砖. 在正式编程前,笔者还要重申上期非常重要的观点:Silverlight多线程主要作用不是在于提高性能,而是在于用户体验.这里要给多线程泼一盆冷水了,多线程与性能提升不是正比关系,如果你使用一个单核CPU的客户端设备,那么即便你创建100个多线程也与单线程的计算性能是一样的,因为一个CPU时间片下只能处

一起谈.NET技术,异步调用与多线程的区别

随着拥有多个硬线程CPU(超线程.双核)的普及,多线程和异步操作等并发程序设计方法也受到了更多的关注和讨论.本文主要是想探讨一下如何使用并发来最大化程序的性能. 多线程和异步操作的异同 多线程和异步操作两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性.甚至有些时候我们就认为多线程和异步操作是等同的概念.但是,多线程和异步操作还是有一些区别的.而这些区别造成了使用多线程和异步操作的时机的区别. 异步操作的本质 所有的程序最终都会由计算机硬件来执行,所以为了更好的理解异步操作的本质,我们