大概有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 系统,能够提供给用户构造图形用户界面的强大功 ...
随机推荐
-
Oracle中如何实现Mysql的两表关联update操作
在看<MySQL 5.1参考手册>的时候,发现MySQL提供了一种两表关联update操作.原文如下: UPDATE items,month SET items.price=month.p ...
-
PE530 : GCD of Divisors
\[\begin{eqnarray*}ans&=&\sum_{i=1}^nf(i)\\&=&\sum_{i=1}^n\sum_{d|i}\gcd(d,\frac{i}{ ...
-
OC-点语法
点语法的本质:方法调用 #import <Foundation/Foundation.h> #import "Person.h" int main(int argc, ...
-
bash脚本编程之二 条件判断and 逻辑运算
1.条件测试结构 1) if/then结构: 判断命令列表的退出码是否为0,0为成功. 如果if和then在条件判断的同一行上的话, 必须使用分号来结束if表达式: if和then都是关键字. 关键字 ...
-
Post-office 树状数组
Post office 题目描述 There are N(N<=1000) villages along a straight road, numbered from 1 to N for si ...
-
bundle update: env: ruby_executable_hooks: No such file or directory
please open a bug here: https://github.com/mpapis/executable-hooks/issues as a temporary fix try: rv ...
-
简单的HTML注册界面
<html><head><title>我的第一个HTML页面</title></head><body><center> ...
-
4. leetcode 461. Hamming Distance
The Hamming distance between two integers is the number of positions at which the corresponding bits ...
-
C# 使用 CancellationTokenSource 终止线程
http://blog.csdn.net/hezheqiang/article/details/51966511 我们在多线程中通常使用一个 C# 使用 CancellationTokenSource ...
-
Jmeter二次开发代码(2)
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreem ...