C#中BeginInvoke与EndInvoke
C#中BeginInvoke与EndInvoke
C#中BeginInvoke与EndInvoke普通方法运行,是单线程的,如果中途有大型操作(如:读取大文件,大批量操作数据库,网络传输等),都会导致方法阻塞,表现在界面上就是,程序卡或者死掉,界面元素不动了,不响应了。
异步方法很好的解决了这些问题,异步执行某个方法,程序立即开辟一个新线程去运行你的方法,主线程包括界面就不会死掉了。
异步调用并不是要减少线程的开销, 它的主要目的是让调用方法的主线程不需要同步等待在这个函数调用上, 从而可以让主线程继续执行它下面的代码.
在C#中使用线程的方法很多,使用委托的BeginInvoke和EndInvoke方法就是其中之一。BeginInvoke方法可以使用线程异步地执行委托所指向的方法。然后通过EndInvoke方法获得方法的返回值(EndInvoke方法的返回值就是被调用方法的返回值),或是确定方法已经被成功调用。
一、BeginInvoke方法
用于启动异步调用
1、定义
public IAsyncResult BeginInvoke(<输入和输出变量>,回调函数callback , 附加信息AsyncState)
2、函数返回值类型
public interface IAsyncResult
{
object AsyncState{ get;} //如果有回调函数的话该参数用于保存要传递给回调函数的参数值
WaitHandle AsyncWaitHandle{ get;}
bool CompletedSynchronously{ get;}
bool IsCompleted{ get;} //保存方法是否执行结束,我们可以通过该属性的值来判断异步方法是否执行结束
}
3、说明
(1).BeginInvoke返回IasyncResult,可用于监视调用进度。
(2).结果对象IAsyncResult是从开始操作返回的,并且可用于获取有关异步开始操作是否已完成的状态。
(3).结果对象被传递到结束操作,该操作返回调用的最终返回值。
(4).在开始操作中可以提供可选的回调。如果提供回调,在调用结束后,将调用该回调;并且回调中的代码可以调用结束操作。
(5).如果需要将一些额外的信息传送给回调函数,就将其放入BeginInvoke()方法的第3个参数asyncState中。注意到这个参数的类型为Object,所以可以放置任意类型的数据。如果有多个信息需要传送给回调函数,可以将所有要传送的信息封状到一个Struct变量,或者干脆再定义一个类,将信息封装到这个类所创建的对象中,再传送给BeginInvoke()方法。
二、EndInvoke方法
用于检索异步调用结果
1、定义
public <方法返回值类型>EndInvoke(<声明为ref或out的参数>, IAsyncResult result )
2、说明
(1).result参数由BeginInvoke()方法传回。.NET借此以了解方法调用是否完成。
(2).当EndInvoke方法发现异步调用完成时,它取出此异步调用方法的返回值作为其返回值,如果异步调用方法有声明为ref和out的参数,它也负责填充它。
(3).在调用BeginInvoke后可随时调用EndInvoke方法,注意:始终在异步调用完成后调用EndInvoke。
(4).如果异步调用未完成,EndInvoke将一直阻塞到异步调用完成。
(5).EndInvoke的参数包括需要异步执行的方法的out和ref参数以及由BeginInvoke返回的IAsyncResult。
三、BeginInvoke与EndInvoke实例
1、直接使用EndInvoke方法来获得返回值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
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秒
int result = task.EndInvoke(asyncResult);
Console.WriteLine(result);
}
}
}
实例说明
(1)、在运行上面的程序后,由于newTask方法通过Sleep延迟了2秒,因此,程序直到2秒后才输出最终结果(一个随机整数)。
(2)、如果不调用EndInvoke方法,程序会立即退出,这是由于使用BeginInvoke创建的线程都是后台线程,这种线程一但所有的前台线程都退出后(其中主线程就是一个前台线程),不管后台线程是否执行完毕,都会结束线程,并退出程序。
2、使用轮询等待异步调用完成:使用IAsyncResult的IsCompleted属性来判断异步调用是否完成
当调用EndInvoke方法获得调用结果时,整个程序就象死了一样,依然要等待异步方法执行结束,这样做用户的感觉并不会太好,因此,我们可以使用 asyncResult来判断异步调用是否完成,并显示一些提示信息。这样做可以增加用户体验。
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace AsyncCalculateFolderSize2
{
class Program
{
//计算指定文件夹的总容量
private static long CalculateFolderSize(string FolderName)
{
if (Directory.Exists(FolderName) == false)
{
throw new DirectoryNotFoundException("文件夹不存在");
}
DirectoryInfo RootDir = new DirectoryInfo(FolderName);
//获取所有的子文件夹
DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
//获取当前文件夹中的所有文件
FileInfo[] files = RootDir.GetFiles();
long totalSize = 0;
//累加每个文件的大小
foreach (FileInfo file in files)
{
totalSize += file.Length;
}
//对每个文件夹执行同样的计算过程:累加其下每个文件的大小
//这是通过递归调用实现的
foreach (DirectoryInfo dir in ChildDirs)
{
totalSize += CalculateFolderSize(dir.FullName);
}
//返回文件夹的总容量
return totalSize;
}
//定义一个委托
public delegate long CalculateFolderSizeDelegate(string FolderName);
static void Main(string[] args)
{
//定义一个委托变量引用静态方法CalculateFolderSize
CalculateFolderSizeDelegate d = CalculateFolderSize;
Console.WriteLine("请输入文件夹名称(例如:C:\\\\Windows):");
string FolderName = Console.ReadLine();
//通过委托异步调用静态方法CalculateFolderSize
IAsyncResult ret = d.BeginInvoke(FolderName, null, null);
Console.Write ("正在计算中,请耐心等待");
//每隔2秒检查一次,输出一个“."
while (ret.IsCompleted == false)
{
Console.Write(".");
System.Threading.Thread.Sleep(200);
}
//阻塞,等到调用完成,取出结果
long size = d.EndInvoke(ret);
Console.WriteLine("\\n计算完成!\\n文件夹{0}的容量为:{1}字节", FolderName, size);
}
}
}
3、使用轮询等待异步调用完成:使用IAsyncResult的AsyncWaitHandle.WaitOne
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace AsyncCalculateFolderSize3
{
class Program
{
//计算指定文件夹的总容量
private static long CalculateFolderSize(string FolderName)
{
if (Directory.Exists(FolderName) == false)
{
throw new DirectoryNotFoundException("文件夹不存在");
}
DirectoryInfo RootDir = new DirectoryInfo(FolderName);
//获取所有的子文件夹
DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
//获取当前文件夹中的所有文件
FileInfo[] files = RootDir.GetFiles();
long totalSize = 0;
//累加每个文件的大小
foreach (FileInfo file in files)
{
totalSize += file.Length;
}
//对每个文件夹执行同样的计算过程:累加其下每个文件的大小
//这是通过递归调用实现的
foreach (DirectoryInfo dir in ChildDirs)
{
totalSize += CalculateFolderSize(dir.FullName);
}
//返回文件夹的总容量
return totalSize;
}
//定义一个委托
public delegate long CalculateFolderSizeDelegate(string FolderName);
static void Main(string
标签:多线程
您可能感兴趣
- python多线程实现(python多线程并发让两个LED同时亮的方法)
- python 多线程与多进程(python 多线程串行和并行的实例)
- tomcat 多线程并发cpu(Tomcat使用线程池处理远程并发请求的方法)
- python的多线程比多进程效率高(Python中单线程、多线程和多进程的效率对比实验实例)
- python中的多线程详解(python多线程抽象编程模型详解)
- php怎么实现多线程(PHP实现的多进程控制demo示例)
- python多线程超时设置(解决python线程卡死的问题)
- python多线程有两个参数怎么传(python从子线程中获得返回值的方法)
- 如何学会python多线程(Python3多线程基础知识点)
- ftp上传工具使用方法(CuteFTP多线程FTP上传下载工具功能介绍)
- phpcurl请求能在日志里记录吗(php使用curl模拟多线程实现批处理功能示例)
- python多进程与多线程详解(Python线程之定位与销毁的实现)
- python开启多线程(python 多线程重启方法)
- python计算csv的行数(对Python 多线程统计所有csv文件的行数方法详解)
- python多线程多进程运行场景(Python多线程同步---文件读写控制方法)
- linux多线程怎么设置(超详细讲解Linux C++多线程同步的方式)
- 泪目 这位 刷屏 的英雄,是全椒人的骄傲(泪目这位刷屏)
- 人从众 火炎焱 全椒再现 正月十六走太平 的魅力(人从众火炎焱全椒再现)
- 官宣 全椒籍明星许海峰 奚秀兰 方芳 王璐瑶携手回家 走太平(全椒籍明星许海峰)
- 以前全椒人是怎么过冬的 满满都是回忆(以前全椒人是怎么过冬的)
- NVIDIA显卡份额冲上88 A饭发愁 游戏优化恐没A卡份了(NVIDIA显卡份额冲上88A饭发愁)
- AMD YES A卡还是N卡 A卡和N卡的区别(AMDYESA卡还是N卡)
热门推荐
- idea如何运行tomcat项目(在IDEA 2020.3.1中部署Tomcat并且创建第一个web项目的过程详解)
- nginx部署配置详解(Nginx服务器基本的模块配置和使用全攻略)
- python操作sql server数据库(Python 数据库操作 SQLAlchemy的示例代码)
- css3渐变色动画代码(CSS3 实现的动态星空背景)
- python随机生成时间戳(python时间序列按频率生成日期的方法)
- python字典的值排序(python 对字典按照value进行排序的方法)
- docker怎么设置参数(浅谈docker --privileged=true参数作用)
- mysql中命令大全(MySQL中ESCAPE关键字的用法详解)
- python八卦图(Python实现九宫格式的朋友圈功能内附“马云”朋友圈)
- docker从一个容器中退出来(Docker容器迁移到其他服务器的5种方法详解)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9