【转】C#绝对新手之C#中的多线程小结
大概有4种方法:
Dispatcher、异步委托、手动多线程、BackgroundWorker,另外还有一个DispatcherTimer,是定时器。
其中Dispatcher与DispatcherTimer相同,是利用在主线程进行任务优先级的排列来模拟多线程,因此其中实质是单线程
,所以大负荷的运算不宜用它们。在异步调用的时候,使用Dispatcher.Invoke(addItem, image);
BackgroundWorker会到线程池去抓一个线程作为工作线程,完成工作后切换回 UI 线程调用你定义的处理完成工作的委
托。每计算出一次值,就会用worker.ReportProgress(percentComplete)通知回调函数,并可在回调函数中更新UI。特
别适合需要更新已完成的百分比的场景。
这些都可以和数据绑定结合起来。
①异步委托还是手动多线程
异步委托:支持线程结束时回调(BeginInvoke方法的的第一个参数),但不支持在外部中断线程,多用于更新UI。
手动线程:支持在外部中断线程(Thread.Abort方法),但不易得到函数的返回值。另外还不能更新UI。因为“Windows
窗体”使用单线程单元 (STA) 模型(WPF窗体也一样),STA模型意味着可以在任何线程上创建窗口,但窗口一旦创建后
就不能切换线程,并且对它的所有函数调用都必须在其创建线程上发生。特别是在注册事件的回调函数中要小心。
委托的用法:
[c-sharp] view plaincopy
- public class MyDelegateTest
- {
- // 步骤1,声明delegate对象
- public delegate bool MyDelegate(string name);
- // 这是我们欲传递的方法,它与MyDelegate具有相同的参数和返回值类型
- public static bool MyDelegateFunc(string name)
- {
- Console.WriteLine("Hello, {0}", name);
- return ture;
- }
- public static voidMain ()
- {
- // 步骤2,创建delegate对象
- MyDelegate md = new MyDelegate(MyDelegateTest.MyDelegateFunc);
- // 步骤3,调用delegate
- Console.WriteLine("Result is {0}", md("sam1111"));
- }
- }
这种调用方法和用委托对象的Invoke一样,都是同步调用,会阻塞当前线程。异步调用需要用BeginInvoke:
[c-sharp] view plaincopy
- class Program
- {
- private static int newTask(int ms)
- {
- Console.WriteLine("任务开始");
- Thread.Sleep(ms);
- Random random = new Random();
- int n = random.Next(10000);
- Console.WriteLine("任务完成");
- return n;
- }
- private delegate int NewTaskDelegate(int ms);
- static void Main(string[] args)
- {
- NewTaskDelegate task = newTask;
- IAsyncResult asyncResult = task.BeginInvoke(2000, null, null); // EndInvoke方法将被阻塞2
- 秒
- //Do Something else
- int result = task.EndInvoke(asyncResult);
- Console.WriteLine(result);
- }
- }
这里的BeginInvoke就是异步调用,运行后立即返回,不会引起当前线程的阻塞。但是在本例程中,因为newTask中要
Sleep 2秒中,如果Do Something else的时间没有2秒的话,EndInvoke还是会引起当前线程的阻塞,因为它要等待
newTask执行完毕。
那能不能不调用EndInvoke,让它自己结束呢?不太好。因为一来BeginInvoke和EndInvoke必须成对调用。即使不需要返
回值,但EndInvoke还是必须调用,否则可能会造成内存泄漏,因为它是利用了线程池资源。二来往往要调用EndInvoke
来获得函数的返回值。
如果是用BeginInvoke来进行轮询操作,EndInvoke是无法返回的,这时可以用一个变量来控制一下:
在我的应用场景里是定义了一个包装类:
[c-sharp] view plaincopy
- class IsNetworkAvailableDelegate
- {
- private IsNetworkAvailableWrapper _available;
- private delegate void MyDelegate();
- private MyDelegate _dele;
- private IAsyncResult _result;
- private bool _running = true;
- private void TryConnect()
- {
- while (this._running)
- {
- try
- {
- Ping _ping = new Ping();
- if (_ping.Send("www.baidu.com").Status == IPStatus.Success)
- this._available.IsNetworkAvailable = true;
- else
- this._available.IsNetworkAvailable = false;
- }
- catch
- {
- this._available.IsNetworkAvailable = false;
- }
- Thread.Sleep(500);
- }
- }
- public IsNetworkAvailableDelegate(IsNetworkAvailableWrapper available)
- {
- this._available = available;
- this._dele = new MyDelegate(this.TryConnect);
- this._result = this._dele.BeginInvoke(null, null);
- }
- public void EndInvoke()
- {
- this._running = false;
- this._dele.EndInvoke(this._result);
- }
- }
要想完全与当前线程异步,可以利用BeginInvoke的第二个参数,设置一个函数执行完成后的回调函数:
[c-sharp] view plaincopy
- private delegate int MyDelegate(int a);
- private int method(int a)
- {
- Thread.Sleep(10000);
- Console.WriteLine(a);
- return 100;
- }
- private void MethodCompleted(IAsyncResult asyncResult)
- {
- if (asyncResult == null) return;
- textBox1.Text = (asyncResult.AsyncState as MyDelegate).EndInvoke(asyncResult).ToString();
- }
- private void button1_Click(object sender, EventArgs e)
- {
- MyDelegate my = method;
- IAsyncResult asyncResult = my.BeginInvoke(MethodCompleted, my);
- }
这样就可以让当前线程完全没有等待的感觉了。
不过有时候,当前线程又想要利用函数执行的时间干点私活,然后在函数执行完成后再做别的,可以用WaitOne方法:
[c-sharp] view plaincopy
- class Program
- {
- public delegate int BinaryOpDelegate(int x, int y);
- static void Main(string[] args)
- {
- Console.WriteLine("***** Async Delegate Invocation *****");
- // Print out the ID of the executing thread.
- Console.WriteLine("Main() invoked on thread {0}.",
- Thread.CurrentThread.ManagedThreadId);
- // Invoke Add() on a secondary thread.
- BinaryOpDelegate b = new BinaryOpDelegate(Add);
- IAsyncResult iftAR = b.BeginInvoke(10, 10, null, null);
- // This message will keep printing until
- // the Add() method is finished.
- //用WaitOne 等待异步委托执行完成
- while (!iftAR.AsyncWaitHandle.WaitOne(1000, true))
- {
- Console.WriteLine("Doing more work in Main()!");
- }
- // Obtain the result of the Add()
- // method when ready.
- int answer = b.EndInvoke(iftAR);
- Console.WriteLine("10 + 10 is {0}.", answer);
- Console.ReadLine();
- }
- #region Very slow addition...
- static int Add(int x, int y)
- {
- // Print out the ID of the executing thread.
- Console.WriteLine("Add() invoked on thread {0}.",
- Thread.CurrentThread.ManagedThreadId);
- 模拟一个花费时间较长的行为
- // Pause to simulate a lengthy operation.
- Thread.Sleep(5000);
- return x + y;
- }
- #endregion
- }
(PS:用lambda语法还可以写出很炫的句子:)
[c-sharp] view plaincopy
- Action<object> action=(obj)=>method(obj);
- action.BeginInvoke(obj,ar=>action.EndInvoke(ar),null);
其实还可以更直接:
[c-sharp] view plaincopy
- new Action<object>((obj) => method(obj)).BeginInvoke(ar=>action.EndInvoke(ar), null);
)
Invoke方法的主要功能就是帮助你在UI线程上调用委托所指定的方法。Invoke方法首先检查发出调用的线程(即当前线程
)是不是UI线程,如果是,直接执行委托指向的方法,如果不是,它将切换到UI线程,然后执行委托指向的方法。
手动线程的调用:
典型的写法是:
[c-sharp] view plaincopy
- public class ProcClass
- {
- private string procParameter = "";
- private string result = "";
- public ProcClass(string parameter)
- {
- procParameter = parameter;
- }
- public void ThreadProc()
- {
- }
- }
- ProcClass threadProc = new ProcClass("use thread class");
- Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
- thread.IsBackground = true;
- thread.Start();
因为Thread调用的函数只能是无参数且无返回值的,因此通常要用类进行包装。
如果线程既需要可中断,又要与UI打交道:
[c-sharp] view plaincopy
- public class ProcClass
- {
- private string procParameter = "";
- private Form1.OutDelegate delg = null;
- public ProcClass(string parameter, Form1.OutDelegate delg)
- {
- procParameter = parameter;
- this.delg = delg;
- }
- public void ThreadProc()
- {
- delg.BeginInvoke("use ProcClass.ThreadProc()", null, null);
- }
- }
- ProcClass threadProc = new ProcClass("use thread class", new OutDelegate(OutText));
- Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
- thread.IsBackground = true;
- thread.Start();
【转】C#绝对新手之C#中的多线程小结的更多相关文章
- 新手数据比赛中数据处理方法小结(python)
第一次参加,天池大数据竞赛(血糖预测),初赛排名1%.因为自己对python不熟悉,所以记录一下在比赛中用到的一些python方法的使用(比较基础细节,大佬绕道): 1.数据初探 data.info( ...
- C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路
C#不用union,而是有更好的方式实现 用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...
- 细说.NET 中的多线程 (一 概念)
为什么使用多线程 使用户界面能够随时相应用户输入 当某个应用程序在进行大量运算时候,为了保证应用程序能够随时相应客户的输入,这个时候我们往往需要让大量运算和相应用户输入这两个行为在不同的线程中进行. ...
- 细说.NET中的多线程 (二 线程池)
上一章我们了解到,由于线程的创建,销毁都是需要耗费大量资源和时间的,开发者应该非常节约的使用线程资源.最好的办法是使用线程池,线程池能够避免当前进行中大量的线程导致操作系统不停的进行线程切换,当线程数 ...
- [转载]ArcGIS Engine 中的多线程使用
ArcGIS Engine 中的多线程使用 原文链接 http://anshien.blog.163.com/blog/static/169966308201082441114173/ 一直都想写 ...
- python中的多线程【转】
转载自: http://c4fun.cn/blog/2014/05/06/python-threading/ python中关于多线程的操作可以使用thread和threading模块来实现,其中th ...
- 拒绝卡顿——在WPF中使用多线程更新UI
原文:拒绝卡顿--在WPF中使用多线程更新UI 有经验的程序员们都知道:不能在UI线程上进行耗时操作,那样会造成界面卡顿,如下就是一个简单的示例: public partial class MainW ...
- java中的多线程——进度2
package src;/*多线程总结:1,进程和线程的概念. |--进程: |--线程:2,jvm中的多线程体现. |--主线程,垃圾回收线程,自定义线程.以及他们运行的代码的位置 ...
- Qt中的多线程编程
http://www.ibm.com/developerworks/cn/linux/l-qt-mthrd/ Qt 作为一种基于 C++ 的跨平台 GUI 系统,能够提供给用户构造图形用户界面的强大功 ...
随机推荐
- HDU 4593 H - Robot 水题
H - RobotTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view.act ...
- [Oracle] Group By 语句的扩展 - Rollup、Cube和Grouping Sets
常常写SQL语句的人应该知道Group by语句的主要使用方法是进行分类汇总,以下是一种它最常见的使用方法(依据部门.职位分别统计业绩): SELECT a.dname,b.job,SUM(b.sal ...
- thinkphp模板中使用自定义函数
注意:自定义函数要放在项目应用目录/common/common.php中. 这里是关键. 模板变量的函数调用格式:{$varname|function1|function2=arg1,arg2,### ...
- MongoDB 主从复制小实验
MongoDB 主从复制小实验 操作环境描述:WIN8 64位操作系统,内装虚拟机为CentOS 5.5 32位系统. 操作描述:跟其他关系型数据库类似,在主库进行数据操作,将数据同步到从节点,从节 ...
- iOS开发——动画篇Swift篇&动画效果的实现
Swift - 动画效果的实现 在iOS中,实现动画有两种方法.一个是统一的animateWithDuration,另一个是组合出现的beginAnimations和commitAnimation ...
- 把json格式对象转成可提交字符串格式,会过滤掉函数 {a: {b: 3}, b: [1], c: "d"} -> a.b=3&b[0]=1&c=d
var json = { name: "任务名称" , scoreRule: "", score: "", // 如果规则表达式不为空,则默 ...
- UNIX标准化及实现之POSIX标准必需头文件
POSIX标准定义的必需头文件 头文件 说明 <dirent.h> 目录项 <fcntl.h> 文件控制 <fnmatch.h> 文件名匹配类型 <glob. ...
- debian防火墙firestarter
Firestarter是一个非常好用的防火墙图形化配置工具,作者和开发者是芬兰人. 首先肯定的说Firestarter防火墙是一款非常优秀的基于GUI图形用户界面下的,完全免费的自由软件,它为中小型L ...
- php对象当参数传递 && php深复制和浅复制
把对象当参数传递给方法,在方法里改过对象后,影响到外面的对象 因为对象是引用传递过去的 class Book { public $name; public function __construct( ...
- 琐碎-关于hadoop2.2.0
HDFS模块功能 namenode:主节点,存储文件的元数据如文件名.文件目录结构.文件属性(生成时间.副本数.文件权限).以及每个文件的块列表和块所在的datanode等: datanode:在本地 ...