1.c#异步介绍

  异步必须基于委托,有委托才有异步

  新建一个window Form程序MyAsync,添加一个按钮,(name)=btnAsync

  后台代码如下:

using System;
using System.Windows.Forms;
using System.Threading;
namespace MyAsync
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate void DoSomethingHandler(string name);//定义一个委托函数
private void btnAsync_Click(object sender, EventArgs e)//btnAsync的点击事件
{
DoSomethingHandler method = new DoSomethingHandler(DoSomething);
       for (int i = ; i <= ; i++)
{
string name = string.Format("Async_{0}", i);
method.BeginInvoke(name, null, null);//新建一个子线程,异步调用
}
}private void DoSomething(string name)//调用函数
{
Console.WriteLine("{0}正在执行,线程ID={1}", name, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep();
Console.WriteLine("{0}结束执行,线程ID={1}", name, Thread.CurrentThread.ManagedThreadId);
}
}
}

  ps:在window Form,我们可以把启动项目的输出类型改成——控制台应用程序,这样在点击事件时,可以看到代码的执行过程

  如:

  

  

  执行结果:

  

  异步调用特点:无序、高效、线程并发

2.异步进阶:对BeginInvoke(name, null, null)参数的了解

  

  第一个参数:委托函数的参数

  第二个参数:AsyncCallback类型的参数,表示异步回调,只有执行完调用函数,才会去执行回调函数

  第三个参数:object类型的参数,用于给回调函数传参,在回调函数使用  [回调函数的参数名].AsyncState 可以使用这个参数,如以下代码的result.AsyncState

using System;
using System.Windows.Forms;
using System.Threading;
namespace MyAsync
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate void DoSomethingHandler(string name);//调用函数的委托
//public delegate void AsyncCallback(IAsyncResult ar);//回调委托,在AsyncCallback上查询定义可以查到,不能在这块重复定义
private void btnAsync_Click(object sender, EventArgs e)
{
DoSomethingHandler method = new DoSomethingHandler(DoSomething);//声明两个委托
AsyncCallback asyncCallback = new AsyncCallback(ThreadCallback);
for (int i = ; i <= ; i++)
{
string name = string.Format("Async_{0}", i);
method.BeginInvoke(name, asyncCallback, "param");//执行完委托的DoSomething方法后才执行回调函数ThreadCallback
}
}
private void ThreadCallback(IAsyncResult result)//回调函数
{
Console.WriteLine("{0}执行了ThreadCallback,参数有{1}", Thread.CurrentThread.ManagedThreadId,result.AsyncState);
}
private void DoSomething(string name)//调用函数
{
Console.WriteLine("{0}正在执行,线程ID={1}", name, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep();
Console.WriteLine("{0}结束执行,线程ID={1}", name, Thread.CurrentThread.ManagedThreadId);
}
}
}

  扩展:当我们把method.BeginInvoke赋值给一个变量的时候,这个变量代表的就是回调函数的参数(为了方便观察,这里去掉了循环,并修改了btnAsync_Click事件)

     private void btnAsync_Click(object sender, EventArgs e)
{
DoSomethingHandler method = new DoSomethingHandler(DoSomething);
AsyncCallback asyncCallback = new AsyncCallback(ThreadCallback);
string name = "Async_{0}";
IAsyncResult result= method.BeginInvoke(name, asyncCallback, "param");//执行完委托的DoSomething方法后才执行回调函数ThreadCallback
Console.WriteLine(result.AsyncState);
}

  通过这个结果,我们可以看到,1代表是并不是这个函数的返回结果,而是输入参数,即1和2是等价的,是由3中两个参数决定的(我也知道这个很神奇)

  而且,因为是异步请求,BeginInvoke新开的一个子线程和主线程是同时进行的,所以Console.WriteLine(result.AsyncState);可以先被执行,即先打印了param

3.带返回值的异步调用

  修改调用函数,使其有return

  在调用函数被修改后,调用函数委托也得修改

  method.EndInvoke(result)方法可以接收返回值,result是IAsyncResult类型,也就是上图的1

  因为1与2等价,所以在回调函数里面也可以使用method.EndInvoke(result)查看调用函数的返回值(使用lambda表达式,不然无法使用method,下面代码的红字),还有一次异步调用只能使用一次method.EndInvoke(result)

  method.EndInvoke(result)方法必须等调用函数执行完才能执行,当调用函数还没return时会卡住界面,即卡住主线程

using System;using System.Windows.Forms;
using System.Threading;
namespace MyAsync
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate int DoSomethingHandler(string name);
private void btnAsync_Click(object sender, EventArgs e)
{
DoSomethingHandler method = new DoSomethingHandler(DoSomething);
AsyncCallback asyncCallback = new AsyncCallback(ThreadCallback);
string name = "Async";
IAsyncResult result=method.BeginInvoke(name, asyncCallback, "param");//执行完委托的调用函数DoSomething后才执行回调函数ThreadCallback
//--------------------如果这里有代码,是可以和BeginInvoke新开的子线程同步执行的----------------//
//-------但是执行到EndInvoke的时候,若是调用函数还没执行完,无法进行下一步,会卡住界面---------//
while (!result.IsCompleted)
{
Console.WriteLine("调用函数还没执行完,请耐心等待....");
Thread.Sleep();//每0.5秒打印一次
}
//-------------可以使用IsCompleted判断是否执行完毕,避免用户以为卡机,关闭程序------------------//
int i = method.EndInvoke(result);//等调用函数执行完才会执行
Console.WriteLine("这里是返回值={0}",i);
}
private void ThreadCallback(IAsyncResult result)//回调函数
{
Console.WriteLine("{0}执行了ThreadCallback,参数有{1}", Thread.CurrentThread.ManagedThreadId,result.AsyncState);
}
private int DoSomething(string name)//调用函数
{
Console.WriteLine("{0}正在执行,线程ID={1}", name, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep();
Console.WriteLine("{0}结束执行,线程ID={1}", name, Thread.CurrentThread.ManagedThreadId);
return ;
}
}
}

  结果:

4.扩展:使用lambda

using System;using System.Windows.Forms;
using System.Threading;
namespace MyAsync
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate int DoSomethingHandler(string name);
private void btnAsync_Click(object sender, EventArgs e)
{
DoSomethingHandler method = new DoSomethingHandler(DoSomething);
//AsyncCallback asyncCallback = new AsyncCallback(ThreadCallback);//使用lambda后可删除回调委托和回调函数
string name = "Async"; method.BeginInvoke(name, t=>
{//回调函数
Console.WriteLine("{0}执行了ThreadCallback,参数有{1}", Thread.CurrentThread.ManagedThreadId, t.AsyncState);
int i = method.EndInvoke(t);//回掉函数内部打印返回值
Console.WriteLine("这里是返回值={0}", i);
}, "param");
}
//private void ThreadCallback(IAsyncResult result)//使用lambda后可删除回调委托和回调函数
//{
// Console.WriteLine("{0}执行了ThreadCallback,参数有{1}", Thread.CurrentThread.ManagedThreadId,result.AsyncState);
//}
private int DoSomething(string name)//调用函数
{
Console.WriteLine("{0}正在执行,线程ID={1}", name, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep();
Console.WriteLine("{0}结束执行,线程ID={1}", name, Thread.CurrentThread.ManagedThreadId);
return ;
}
}
}

  结果:

  这个时候因为method.EndInvoke是在回调函数里面使用的,回调函数又是由子线程执行的,所以只会卡住子线程,主线程并不会被卡住,即界面不会卡住

  而且method.EndInvoke对于每个异步操作只能执行一次,如果在子线程和主线程都出现,会报错

  当然,只在子线程或者主线程出现多次也会报错

5.使用Task框架实现异步

  添加一个新按钮 (name)= AsynsTask

using System;using System.Windows.Forms;
using System.Threading;
namespace MyAsync
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}private void AsynsTask_Click(object sender, EventArgs e)
{
Console.WriteLine("接到任务");
Console.WriteLine("分配任务,用多线程同时进行任务,模拟实际开发中团队同时进行");
TaskFactory taskFactory = new TaskFactory();//实例化一个TaskFactory任务工厂
Action act1 = new Action(() => Coding("kxy", "后台"));//用lambda表达式表示一个无参数无返回值的匿名函数
Action act2 = new Action(() => Coding("fz", "后台"));
Action act3 = new Action(() => Coding("xx", "数据库"));
Action act4 = new Action(() => Coding("flt", "前端"));
Action act5 = new Action(() => Coding("zjx", "前端"));
Task task1 = taskFactory.StartNew(act1);//Task创建并开启一个线程,执行act
Task task2 = taskFactory.StartNew(act2);
Task task3 = taskFactory.StartNew(act3);
Task task4 = taskFactory.StartNew(act4);
Task task5 = taskFactory.StartNew(act5);
List<Task> Ltask = new List<Task>();
Ltask.Add(task1);
Ltask.Add(task2);
Ltask.Add(task3);
Ltask.Add(task4);
Ltask.Add(task5);
Task.WaitAny(Ltask.ToArray());//等待这些线程中某一个执行完再往下执行主线程
Console.WriteLine("<<<开始进行测试>>>");
Task.WaitAll(Ltask.ToArray());//等待这些线程执行完成再往下执行主线程
Console.WriteLine("<<<开发完成,开始部署>>>");
Console.WriteLine("<<<任务完成>>>");
}
private void Coding(string name, string work)
{
Console.WriteLine("线程ID={0} {1} 的工作是 {2}", Thread.CurrentThread.ManagedThreadId, name, work);
Thread.Sleep();
Console.WriteLine("============线程ID={0} {1} 完成工作 {2}", Thread.CurrentThread.ManagedThreadId, name, work);
}
}
}

异步Async的更多相关文章

  1. 同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式

    1. 概念理解        在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式:   同步/异步主要针对C端: 同步:    ...

  2. c# 异步( Async ) 不是多线程

    c# 异步( Async ) 不是多线程   误解 async 在调试 xxxxAsync() 方法的时候,常常会看到调试器界面中会多出一些线程,直觉上误认为 Async 冠名的函数是多线程. 对于 ...

  3. .NET为什么要使用异步(async)编程?⭐⭐⭐⭐⭐

    .NET为什么要使用异步(async)编程? 有几点坐下笔记 ⭐⭐⭐⭐: 1. 同步方法 static void Main(string[] args) { Console.WriteLine($&q ...

  4. 一代版本一代神:利用Docker在Win10系统极速体验Django3.1真实异步(Async)任务

    一代版本一代神:利用Docker在Win10系统极速体验Django3.1真实异步(Async)任务 原文转载自「刘悦的技术博客」https://v3u.cn/a_id_177 就在去年(2019年) ...

  5. 我也来说说C#中的异步:async/await

    序 最近看了一些园友们写的有关于异步的文章,受益匪浅,写这篇文章的目的是想把自己之前看到的文章做一个总结,同时也希望通过更加通俗易懂的语言让大家了解"异步"编程. 1:什么是异步 ...

  6. 请教 C# 异步 async await 问题

    各位园友,之前对C#异步只是肤浅了解,请教一个具体问题. 需求: 前台会发送一个Array,这个数组都是 id的集合,比较大.分两步,首先保存这些id,然后去调用异步方法. 可以正常返回json,也可 ...

  7. Python 进阶 异步async/await

    一,前言 本文将会讲述Python 3.5之后出现的async/await的使用方法,我从上看到一篇不错的博客,自己对其进行了梳理.该文章原地址https://www.cnblogs.com/dhcn ...

  8. 异步 async & await

    1 什么是异步 异步的另外一种含义是计算机多线程的异步处理.与同步处理相对,异步处理不用阻塞当前线程来等待处理完成,而是允许后续操作,直至其它线程将处理完成,并回调通知此线程. 2 异步场景 l  不 ...

  9. 异步async与await的简单探究

    在学习.net core的过程中,到处见到异步的使用,Task.async.await随处可见.有点疑惑,就去了解了下这个过程是怎样的. 下面是一段代码,去看看是怎么执行的吧. 一.看看异步执行的方式 ...

随机推荐

  1. 第十四篇-ImageButton控制聚焦,单击,常态三种状态的显示背景

    这里先用XML设置. myselector.xml <?xml version="1.0" encoding="utf-8"?> <selec ...

  2. jQuery获取节点和子节点文本的方法

    本节主要介绍了jQuery如何获取节点和子节点文本,下面有个示例,大家可以参考下 对于下面的html片段, ? 1 <div id="text_test">test t ...

  3. Unity 网络编程(Socket)应用

    服务器端的整体思路: 1.初始化IP地址和端口号以及套接字等字段: 2.绑定IP启动服务器,开始监听消息  socketServer.Listen(10): 3.开启一个后台线程接受客户端的连接 so ...

  4. HTML学习笔记Day7

    一.position定位属性,检索对象的定位方式 1.语法:{position:static(无特殊定位)/absolute(绝对定位)/relative(相对定位)/fixed(固定定位):} 1) ...

  5. Lucas定理学习笔记(没有ex_lucas)

    题目链接\(Click\) \(Here\) \(ex\_lucas\)实在是不能学的东西...简单学了一下\(Lucas\)然后打算就这样鸽着了\(QwQ\)(奶一口不可能考) 没什么复杂的,证明的 ...

  6. 谈.Net委托与线程——创建无阻塞的异步调用(二)

    了解IAsyncResult 现在我们已经了解,EndInvoke可以给我们提供传出参数与更新后的ref参数:也可以向我们导出异步函数中的异常信息.例如,我们使用BeginInvoke调用了异步函数S ...

  7. CentOS 6.5 64位 安装Nginx, MySQL, PHP

    此篇文章参考了一些网站找的教程,自己遇到了很多坑,写一下自己的安装全过程. 服务器是腾讯云的.安装了centos 6.5系统. 一. 安装Nginx 1.首先安装GCC,make,C++编译器 yum ...

  8. 2017-12-14python全栈9期第一天第三节之python历史

    python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆(中文名字:龟叔)为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言 ...

  9. kubernetes yaml格式的Pod配置文件

    kubernetes yaml文件解析 # yaml格式的pod定义文件完整内容: apiVersion: v1 #必选,版本号,例如v1 kind: Pod #必选,Pod metadata: #必 ...

  10. python css盒子型 浮动

    ########################总结############### 块级标签能够嵌套某些块级标签和内敛标签 内敛标签不能块级标签,只能嵌套内敛标签 嵌套就是: <div> ...