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同时亮的方法)
- tomcat 多线程并发cpu(Tomcat使用线程池处理远程并发请求的方法)
- python多进程与多线程详解(Python线程之定位与销毁的实现)
- 如何学会python多线程(Python3多线程基础知识点)
- python多线程多种方法(详解python多线程之间的同步一)
- ftp上传工具使用方法(CuteFTP多线程FTP上传下载工具功能介绍)
- python多线程有两个参数怎么传(python从子线程中获得返回值的方法)
- laravel多线程处理请求(Laravel 6 将新增为指定队列任务设置中间件的功能)
- python线程池有几种(对python 多线程中的守护线程与join的用法详解)
- python开启多线程(python 多线程重启方法)
- python多线程并发使用场景(对python多线程SSH登录并发脚本详解)
- python的多线程比多进程效率高(Python中单线程、多线程和多进程的效率对比实验实例)
- python多线程多进程运行场景(Python多线程同步---文件读写控制方法)
- phpcurl请求能在日志里记录吗(php使用curl模拟多线程实现批处理功能示例)
- python中的多线程详解(python多线程抽象编程模型详解)
- php脚本控制方法(php swoole多进程/多线程用法示例基于php7nts版)
- 四川旅游攻略(四川旅游攻略自由行攻略)
- 上海迪士尼攻略(上海迪士尼攻略旅游)
- 哪里可以看熊猫(成都哪里可以看熊猫)
- oppo手机的三种录屏方法,你知道有哪些吗(oppo手机的三种录屏方法)
- 吉林神秘传染链跨省 传染源尚未找到,舒兰 封城(吉林神秘传染链跨省)
- 吉林舒兰 封城 聚集性疫情传播链已延至沈阳,有一个细节让人忧心(吉林舒兰封城)
热门推荐
- 支付宝接口中notify_url 与 return_url 的区别
- css文本怎么控制边距(css中text-overflow属性与文本截断详解)
- python变量与对象的关系(Python面向对象程序设计类变量与成员变量、类方法与成员方法用法分析)
- mysql配置多实例
- laravel 数据库实现原理(laravel 数据迁移与 Eloquent ORM的实现方法)
- docker容器缺少很多命令怎么办(解决docker 容器设置中文语言包出现的问题)
- 零基础学php好吗(零基础php编程好学吗)
- IIS “服务器应用程序不可用”的解决方法
- php和java联系(PHP实现与java 通信的插件使用教程)
- linux如何安装php7.1.5环境(vmware linux系统安装最新的php7图解)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9