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多线程同步---文件读写控制方法)
- tomcat 多线程并发cpu(Tomcat使用线程池处理远程并发请求的方法)
- phpcurl请求能在日志里记录吗(php使用curl模拟多线程实现批处理功能示例)
- C# Task实现多线程
- linux多线程怎么设置(超详细讲解Linux C++多线程同步的方式)
- python多线程有两个参数怎么传(python从子线程中获得返回值的方法)
- php怎么实现多线程(PHP实现的多进程控制demo示例)
- python多进程与多线程详解(Python线程之定位与销毁的实现)
- python中的多线程详解(python多线程抽象编程模型详解)
- python线程池有几种(对python 多线程中的守护线程与join的用法详解)
- python线程池如何实现同步(Python mutiprocessing多线程池pool操作示例)
- laravel多线程处理请求(Laravel 6 将新增为指定队列任务设置中间件的功能)
- python 多线程与多进程(python 多线程串行和并行的实例)
- php脚本控制方法(php swoole多进程/多线程用法示例基于php7nts版)
- python多线程实现(python多线程并发让两个LED同时亮的方法)
- python多线程多种方法(详解python多线程之间的同步一)
- 文莱旅游攻略(文莱旅游攻略介绍)
- 马来西亚旅游攻略(马来西亚旅游攻略自由行攻略)
- 缅甸旅游攻略(缅甸旅游攻略必去景点推荐)
- 《庆余年2》新消息,原班人马,肖战特别出演,这才是最好的安排(庆余年2新消息原班人马)
- 宁夏灵武恐龙化石发现始末(宁夏灵武恐龙化石发现始末)
- 到了岁末 临门一脚 节点,天台综合督评会目标直指 全年红(到了岁末临门一脚)
热门推荐
- ref和out区别有哪些
- js中parent和opener的区别
- 简述css在html页面中的使用方法(10分钟理解CSS BFC原理及其应用)
- sqlserver游标使用场景(解析SQL Server聚焦移除Bookmark Lookup、RID Lookup、Key Lookup)
- mysql binlog如何查看(MySQL binlog_ignore_db 参数的具体使用)
- mysql分库分表视图(MySQL分库分表与分区的入门指南)
- vue 动态绑定指令(vue动态绑定图标的完整步骤)
- python人脸识别库有几个(Python人脸识别第三方库face_recognition接口说明文档)
- 史上最全的css布局教程(详解CSS经典布局之Sticky footer布局)
- dedecms栏目内容怎么插入分页符(dedecms自动给已经发布过的文章中的关键词加超链接)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9