Asp.Net基本知识理论概述

本文对Asp.Net相关理论进行了全面整理,涵盖Ado.Net、Session、Cookie、Cache等内容。介绍了各部分的概念、特点、使用方法及注意事项,如Ado.Net用于C#程序访问数据库,Session用于跨页面传递数据,还讲解了多线程、异步编程等知识。

Asp.Net理论整理

Ado.Net

Ado.Net是一组向.Net FrameWrok程序员公开数据访问的类。主要用于完成C#程序访问数据库;
Ado.Net主要由以下几个类组成;
Connection 数据库链接对象;
Command 数据库命令对象;
DataReader 数据读取对象;
DataSet 数据容器
DataAdapter 数据缓冲池对象
DataTable 数据表格对象
SqlCommandBuilder
用来为SqlDataAdapter 自动生成SQL语句,批量更新DataSet 不用再为SQL DataAdapter编写Insert/Delete/UpdateCommand语句;如果对DataSet(内存的数据)的修改可以直接自动更新到数据库中;代码示例

//只展示核心代码
   					#region dataset 批量操作数据 
               SqlCommandBuilder bulid = new SqlCommandBuilder(adapter);
               DataTable  dt = ds.Tables[0];
                 dt.Rows[3][2] = "ceshi";
                adapter.Update(ds.Tables[0].GetChanges());
                #endregion

Ado.Net 讲解
Ado.Net官方文档

Session

概念:用于存储特定的用户会话所需要的信息;Session对象的引入是为了弥补http(无状态保持协议)不足;
使用Session的目的:跨页面传递数据;

特点 :
系统为每个访问者都设立一个独立的Session对象,用于存储Session变量,并且Session对象不会相互影响;
一个页面存入Sessioin后整个网站中所有的也i按都可以获取当前值

使用要求;
Session与cookie 是紧密相关的,可以将其简单的理解为Session就是服务器的“Cookie”,如果用户浏览器不支持Cookie或者浏览器禁用Cookie,系统将无法使用Session,对于用户来说不同的用户用不同的Session对象来记录,当用户启用Session时,Asp会自动生成一个SessionId,在新会话开始,服务器将SessionID当作Cookie存储在用户的浏览器当中;

Session存放位置
可以通过设置配置文件 进行配置节点 :

<system.web>
<sessionState mode="Off|InProc|StateServer|SQLServer"cookieless="true|false"timeout="number of minutes"stateConnectionString="tcpip=server:port"sqlConnectionString="sql connection string"stateNetworkTimeout="number of seconds"/>
</system.web>

配置文件节点讲解
mode:设置将Session信息存储到哪里

​ Off:不使用Session功能;

​ InProc :将Session存储在IIS进程内,这是默认值,也最常用(优点是简单,性能最高。但是当重启IIS服务器时Session丢失。);

​ StateServer :将Session存储在ASP.NET状态服务进程中(重新启动Web应用程序时保留会话状态,并使会话状态可以用于网络中的多个Web服务器。);

​ SQLServer :将Session存储在SQL Server中(存储在内存和磁盘中,服务器挂掉重启后都还在)。

cookieless:设置客户端的Session信息存储到哪里

​ true 使用Cookieless模式;这时客户端的Session信息就不再使用Cookie存储了,而是将其通过URL存储。

​ false 使用Cookie模式,这是默认值。

timeout 设置经过多少分钟后服务器自动放弃Session信息。默认为20分钟。

stateConnectionString 设置将Session信息存储在状态服务中时使用的服务器名称和端口号,例如:"tcpip=127.0.0.1:42424”。当mode的值是StateServer是,这个属性是必需的。(默认端口42424)。

sqlConnectionString 设置与SQL Server连接时的连接字符串。例如"data source=localhost;Integrated Security=SSPI;Initial Catalog=joye"。当mode的值是SQLServer时,这个属性是必需的。

stateNetworkTimeout 设置当使用StateServer模式存储Session状态时,经过多少秒空闲后,断开Web服务器与存储状态信息的服务器的TCP/IP连接的。默认值是10秒钟。

Sessioin操作
存 :

Session["UserAccount"]="admin"

 string account=Session["UserAccount"].toString();

删除

   //删除某一个key名的session
        Session.Remove("UserAccount");
        //删除所有的Session
        Session.Clear();
        //删除所有的Session包括对象本身    当用户退出的时候 使用Abandon
        Session.Abandon();

失效条件:
浏览器关闭 ,会话消失;
时间到达会话消失;
通过代码删除会话;

Cookie

概念:
Cookie是一种客户端技术,服务器把每个用户的数据以cookie的形式写给各自的浏览器,当用户访问服务器的web资源时就会带着各自的数据;

Cookie 特点;

cookie 只是一个字符串 ,并没有任何执行能力;

大多数浏览器规定Cookie的大小不能超过4K ,每个站点能够保存的cookie不超过20个,所用的cookie保存不能超过300个;

cookie 的安全性较低,因而不要在cookie中保存机密信息,例如用户民、密码、信用卡号;cookie不要保存不应该让用户保存的数据;

cookie操作共分为.net 服务端操作 和Jscript前端操作
在这里仅介绍.NET操作Cookie

            //cookie格式:Name=VALUE;Expires=1723571562375000
            
           	//存
            HttpCookie cookie = new HttpCookie("MyCookie");
            cookie.Value = "Hello";
            cookie.Expires = System.DateTime.Now.AddDays(30);
            cookie.Path = "/Domain/";
            // 服务器创建了一个Cookie
            Response.Cookies.Add(cookie);
            
            //取
               HttpCookie cookie = Request.Cookies["MyCookie"];
            if (cookie != null)
            {
                Response.Write(cookie.Name);
                Response.Write(cookie.Value);
            }
            //删除
             //注意:cookie不能直接删除,如果需要删除 那么要重新创建一个和目标cookie同名的cookie
            //并且让他的有效期过期
            HttpCookie cookie = new HttpCookie("MyCookie");
            cookie.Expires = System.DateTime.Now.AddMilliseconds(-1);    
   
            // 服务器创建了一个Cookie
            Response.Cookies.Add(cookie);

使用Js操作Cookie

注意事项:
在使用cookie时应当注意cookie的工作原理,大小限制以及安全;

  1. cookie的存储位置,客户端的cookie文件夹内 Ie浏览器少有特殊;
  2. 存储的数据类型:存储为字符串类型;
  3. 状态使用范围:当前请求的上下文都能获取cookie,cookie对每个用户来说都是独立的;
  4. 存储的大小限制:cookie大小不能超过4K、
  5. 生命周期:添加cookie时可以设定过期时间;超过时间自动失效;
  6. 安全和性能:安全性较低,敏感数据建议加密后保存;

Cache

Cache是分布在服务器上的公共内存片,所谓公共既是只要Cache一旦创建所有的客户端都能对其进行访问;与session相比 Session只能面向单个用户;
cache 和session ,cookie一样都用时间限制。唯一一点cache和session可以设置滑动过期时间,所谓滑动就是只有当操作停止相应的时间才会过期;
cache可以存放任何对象;

如何使用Cache:

这里需要注意一下 HttpContext和HttpRunTime下使用Cache是完全一样的。

创建cache
  在.Net环境下通过Cache.Insert(string key,object o)方法创建。其中key 代表cache的ID,o代表存到cache里的对象。
- 销毁cache.
  通过方法Cache.Remove(string key)其中key 代表cache的 ID.
- 调用cache.
  Cache支持装箱/拆箱操作。如你可以把一个DataSet对象ds通过Cache.Insert(“dsCache”,ds)的方式存到Cache中,可以通过拆箱操作 DataSet ds = (DataSet)Cache[“dsCache”]来访问它。

何时使用Cache:
Cache一般适用于数据较为固定,使用较为繁琐的地方;例如进销存系统的产品信息,;

缓存依赖:缓存依赖通过检测依赖项的操作来通知缓存是否过期的一种机制;
缓存中的依赖项可以是数据库,也可以是文件;

缓存依赖案例:在这里不在进行讲解,具体和浏览博客Cache缓存依赖

 /// <summary>
        /// 获取当前应用程序指定CacheKey的Cache对象值
        /// </summary>
        /// <param name="CacheKey">索引键值</param>
        /// <returns>返回缓存对象</returns>
        public static object GetCache(string CacheKey)
        {
            System.Web.Caching.Cache objCache = HttpRuntime.Cache;
            return objCache[CacheKey];
        }
        /// <summary>
        /// 设置以缓存依赖的方式缓存数据
        /// </summary>
        /// <param name="CacheKey">索引键值</param>
        /// <param name="objObject">缓存对象</param>
        /// <param name="cacheDepen">依赖对象</param>
        public static void SetCache(string CacheKey, object objObject, System.Web.Caching.CacheDependency dep)
        {
            System.Web.Caching.Cache objCache = HttpRuntime.Cache;
            objCache.Insert(
                CacheKey,
                objObject,
                dep,
                System.Web.Caching.Cache.NoAbsoluteExpiration, //从不过期
                System.Web.Caching.Cache.NoSlidingExpiration, //禁用可调过期
                System.Web.Caching.CacheItemPriority.Default,
                null);
        }
        protected void Page_Load(object sender, EventArgs e)
        {
            string CacheKey = "cachetest";
            object objModel = GetCache(CacheKey);//从缓存中获取
            if (objModel == null) //缓存里没有
            {
                objModel = DateTime.Now;//把当前时间进行缓存
                if (objModel != null)
                {
                    //依赖 C:\\test.txt 文件的变化来更新缓存
                    System.Web.Caching.CacheDependency dep = new System.Web.Caching.CacheDependency("C:\\test.txt");
                    SetCache(CacheKey, objModel, dep);//写入缓存
                }
            }
            Response.Write(objModel.ToString());
        }

Transfer

Asp.Net Servet.Transfer ()是在页面之间传值,其实用起来更像是response.Redirect()重定向

两者使用起来还是有写区别:

  • Transfer 只能跳转到本地路径的页面,redirect相对更加灵活能够跳转到网络路径;
  • Transfer 能够将页面参数传到指定页面
  • 使用时transfer跳转到别的页面浏览器的URL地址不会发生变化,使用redirect则会让地址发生变化;
  • 使用transfer只需要在服务端进行一次通讯即可,使用redirect则需要进行两次通讯。简单理解就是transfer 跳页不是服务器响应跳转,而是服务器直接跳转,客户端对页面跳转毫不知情,因而浏览器URL不会发生变化。使用redirect则是需要将响应结果回传到客户端由客户端发送页面跳转请求;

Transfer 用法参考

Ajax和一般处理程序

Ajax

一部网页技术实现,实现不刷新与服务端进行交互;
优点: 交互效果较好,不会阻塞Ui线程;
缺点:对爬虫不太友好,原生的Ajax编写麻烦,破坏浏览器前进后退功能

一般处理程序

一般处理程用于处理远程接口功能,相比页面Page,一般处理程序只保留HTTP所需要的功能,更加轻量化,是实现网络接口方式之一,其余两种方式是Mvc、 WebApi。

一般处理程序是实现 IHttpHandler接口的特殊类,是作为外部请求的目标程序的前提如果没有实现此接口将无法被浏览器请求。

一般处理程序是由支持Asp.Netde服务器调用和执行,一个一般处理程序可以用于处理它对应的一个或者一组URL地址的访问请求,接受请求报文并新产生响应报文.

用途:
  1.获取客户端通过HTML的Form表单提交的数据和URL参数

2.创建对客户端的响应消息内容

3.访问服务器端的文件系统

4.连接数据库并开发基于数据库的应用

5.调用其他类

LINQ

ORM

多线程

在讲解C#的多线程之前 .我们先来了解了几个关于计算机操作系统的几个基本知识点:

进程:进程是计算机中程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位;是操作系统结构的基础;在计算机程序中进程便是构成运行程序的资源的集合,这些资源包括虚地址空间,文件句柄,和许多其他程序的运行所需要的资源 ;

线程 :线程是进程内部的一个执行单元 ,在默认情况下一个进程只有一个线程,及其从程序的开始执行直到执行结束,但是通过技术手段进行让进程由单个线程转化为多个线程,这个便是接下来将要讲解的多线程;

以上两点只是多线线程的前菜预热,在正式讲解多线程的时候,先来了解异步;

异步

概念:程序调用其中一个方法,如果程序不等到此方法执行完成就执行接下来的方法 ,此方法的执行方式便是异步, 使用此方法编写程序便是异步编程,简单理解就是程序不需要等待方法出结果就可以执行下一部分代码 ;

当然如此笼统的概念还是很难让人理解的,接下来就进行详细的讲解,先来理解一下并行;

并行:一般指的是并行计算,是指同一时刻有多条指令被执行,这些指令可能被执行在同一Cpu上,或者多个物理主机甚至多个网络之中;
当然这样说会更晕头转向,简单理解并行就是同一时刻 有几个人帮你干活,原本非并行情况下,你的活只能让你一个人干完,并行就是由多个人同时帮你干;在计算机程序中,程序不需要等方法计算结果,就可以就可以直接执行下面的代码,也就是说 程序让“别人”帮它执行方法进行数据计算,自己接着干干下面的活,

异步特点:
不会造成线程阻塞,就是程序在执行代码时,进行不了其他操作;
异步可以启用额外的线程去执行任务;
异步不会缩短任务的时间,只是将任务分给多个线程同时处理,缩短的耗时。

异步方法调用

Console.WriteLine("****************异步调用开始**********************");
    for (int i = 0; i < 5; i++)
       {
          string name = string.Format("异步调用{0}", i);
          DoHandler method = DoSomething;
          method.BeginInvoke("异步调用", null, null);
       }
Console.WriteLine("****************异步调用结束**********************");

///含有返回值
  Console.WriteLine("****************异步待返回值进阶调用开始**********************");
    Func<string, long> method = DoSomethingReturn;
    //主线程中使用返回值
    IAsyncResult result = method.BeginInvoke("异步带返回值调用", t =>
    {
       long iresult = method.EndInvoke(t);
       Console.WriteLine("这里是异步返回值,当前线程={0},计算结果是{1}", Thread.CurrentThread.ManagedThreadId, iresult);
            
    }, null);

异步执行回调函数


  Console.WriteLine("****************异步进阶调用开始**********************");
            for (int i = 0; i < 5; i++)
            {
                string name = string.Format("异步调用{0}", i);
                DoHandler method = DoSomething;
                AsyncCallback callback = t => Console.WriteLine("当前完成的线程是ID={0},状态参数:{1}", Thread.CurrentThread.ManagedThreadId, t.AsyncState);
                //关注参数
                //参数2:回调函数
                //参数3:回调获得
                IAsyncResult result = method.BeginInvoke(name, callback, "Admin");
 
            }
 Console.WriteLine("****************异步进阶调用结束**********************");

执行异步方法 获取执行结果

//方式一
result.AsyncWaitHandle.WaitOne(-1);//线程一直等待
//方式二
while (!result.IsCompleted)//判断是否结束
     {
         Thread.Sleep(100);
         Console.WriteLine("请继续等待...");//类似进度条
      }
      //方式三
      method.EndInvoke(result)

以上三种方式均是让主线程进入等待状态,造成主线程阻塞

异步的优缺点:
因为异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变量(即使无法完全不用,最起码可以减少 共享变量的数量),减少了死锁的可能。
缺点:
编写异步操作的复杂程度较高,程序主要使用回调方式进行处理,与普通人的思维方式有些出入,难以调试。
使用异步对Cpu的性能要求较高;多线程同样由这一缺点;

适用范围:
在执行I/O操作;
网络读写 调用接口;
数据库操作;
Webservice (有点像调用接口)

但对于长时间Cpu 运算的场合,图形处理,算法执行(任务无法分割)不适合使用异步

注意:
很多人往往会使用线程来执行耗时较长的I/O操作,也导致很多人就误认为异步==多线程; 个人理解 异步是一种思想,多线程是实现异步的一种方式(还希望大佬能够及时指正一下),
总结:异步适合与一些耗时操作并且这些操作是可拆分的任务

失效条件
浏览器关闭,会话消失;
时间到,会话消失;
代码删除 ;

多线程

说完异步 接下来介绍多线程;
从上面的并行计算我们可以知道程序可以让“别人”帮他完成任务,而这个别人就是程序中的线程,实现程序进行并行计算的方式/技术就叫做多线程。到这我们不难发现 多线程就是:同一个计算机进程中包含多个线程(包含其数据结构,上下文和代码片段)协作运行,在多核计算机上多个线程将有机会同时运行于多个核,如果计算机进行的是计算则形成并行计算.

如果还有些不理解 来个案例

**1**
 界面上点击某个按钮后,需要执行一个非常耗时的操作,如果不使用多线程,就只能傻等操作返回。
 使用多线程,点击按钮之后,开辟1个新线程后台去执行这个耗时操作,前台界面继续执行其他菜单目录,录入数据等。

**2**
 有个操作,1个线程需要20分钟完成,现在的多核cpu,可以真正同一时刻运行多个线程。
 假设是双核cpu,同一时刻运行2个线程,操作就只需要10分钟可以完成。

开启线程实现方式 :(共四种)

委托:使用beginInvoke 开启线程;thread类start/线程工厂 开启线程, 使用线程池;使用Task
开启线程的四种方式

多线程优点:
提高程序的执行效率;
提高cpu的利用率;
缺点:
对硬件要求较高

线程数量:
理想的线程数量<=CPU 核心数量;

Thread

前面我们说到开启线程的四种方式 ;委托 BeginInvoke() 开启线程不再阐述 详见,使用委托开启线程 (网上博客多的是)

接下来使用Thread类开启线程:

Thread thread=new Thread(方法);
thread.start();
//线程的挂起
Thread.sleep();
//线程的阻塞;
Thread.join();
//线程终止
thread.abort();

线程终止不推荐使用,线程终止不安全并且不可控;

在线程中,线程又分为前台线程和后台线程;

Net的公用语言运行时(Common Language Runtime,CLR)能区分两种不同类型的线程:前台线程和后台线程。这两者的区别就是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。

一般后台线程用于处理时间较短的任务,如在一个Web服务器中可以利用后台线程来处理客户端发过来的请求信息。而前台线程一般用于处理需要长时间等待的任务,如在Web服务器中的监听客户端请求的程序,或是定时对某些系统资源进行扫描的程序。

前后台线程的重要性和区别:
1、有前台,不关闭;
如果线程作为前台线程,可能导致Ui线程已经关闭,但实际上还有前台线程在运行,所以程序并没有真正的关闭;
2、无前台,全关闭;
当程序的前台线程全部关闭,后台线程会自动关闭,后台线程中程序正在运行仍会关闭;

线程转递参数:
在多线程中传递参数共有两种方式;
使用ParameterizedThreadStart 委托;

使用此种方式传递参数需要注意一下几点:
只能传递object类型参数,因为thread类中只接受threadstart委托,并且该委托是一个无参无返回值的,所以此处使用ParameterizedThreadStart

//代码示例
    ParameterizedThreadStart pts1 = DoSomething;
     Thread thread = new Thread(pts1);
     object name = "线程参数";
     thread.Start(name);

方式二:使用匿名函数 Lambda(开发程序推荐)

 string hi = "张三";
 Thread thread = new Thread(() =>
 {
     DoSomething(hi);
 });
 thread.Start();

线程异常:

注意:只要有线程抛出异常,整个程序就会停止。所以,异常必须处理。

对创建线程try catch没用,需要对线程中调用的函数添加异常处理代码

static void Main(string[] args)
{
    try // 无用的 try catch
    {
        Thread thread = new Thread(SayHi);
        thread.Start();
    }
    catch (Exception ex)
    {
        // 不会打印错误
        Console.WriteLine(ex.ToString());
    }
}
//正确
static void Main(string[] args)
{
    Thread thread = new Thread(SayHi);
    thread.Start();
    thread.Join();
}
static void SayHi()
{
    try
    {
        Console.WriteLine("hi");
        throw new Exception("error");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

线程安全:
由于多个线程同时对程序中静态资源进行处理,而未对静态资源进行同步处理;造成了脏读;

static void Main(string[] args)
{
    Thread thread = new Thread(
        () => { Check("张三"); });
    Thread thread2 = new Thread(
        () => { Check("李四"); });
    thread.Start();
    thread2.Start();
    thread.Join();
    thread2.Join();
}
static void Check(string name)
{
    User.Name = name;
    string format = @"{0} = {1}";
    for (int i = 0; i < 10; i++)
    {
        string s = string.Format(format, name, User.Name);
        Console.WriteLine(s);
        Thread.Sleep(10);
    }
}
public class User
{
    public static string Name { get; set; }
}

解决方案:
使用lock的操作;
将其同种的共享资源设为临界区,所谓临界区就是同一时刻只能有一个线程来操作临界区的代码,当一个线程位于代码的临界区时,另一个线程不能进入临界区,如果视图进入临界区,则只能进入等待(即被阻止),直到已经进入临界区的线程访问结束,并释放锁旗标;

代码示例

static readonly object obj = new object();
// -------------------------
lock (obj)
{
    User.Name = name;
    string format = @"{0} = {1}";
    for (int i = 0; i < 10; i++)
    {
        string s = string.Format(format, name, User.Name);
        Console.WriteLine(s);
        Thread.Sleep(10);
    }
}

多线程缺点:
线程占用一定资源,比如内存,cpu,创建和销毁操作都比较昂贵;
线程调度器需要管理线程,系统大量创建线程,会导致内存不够使用,线程调度器繁忙;
多个线程同时竞争同一静态资源时,容易造成死锁现象;

线程池:

正如上面多线程的缺点一样,线程的创建和销毁都是比较昂贵的,为解决此问题,Asp.Net中自己设定了一个线程池,有底层统一调配;

实现思路: 实现创建好几个线程对象,需要的就从线程池中分配,使用结束返回线程池中;

ThreadPool.QueueUserWorkItem((obj) =>
 {
      DoSomething();
      Console.WriteLine(obj);

},"admin");

使用线程池需要注意一下几点:
线程池,处理的方法只适合短时操作,不要阻塞线程池线程;‘
线程池中的线程都是后台线程;
线程池中的线程池数量是有上限的;
Asp.Net 会使用自己的线程池;
使用线程池时当并发请求超过一定数量(默认线程池中线程数量),则会进行排队。所以并行的请求处理时间会被延长
总结:线程池避免了系统的频繁创建和销毁线程,并且线程池的线程全是后台线程,适合用于处理可随时处理停止的方法(耗时较短的方法)究其原因便是后台线程会随着前台线程关闭强制停止。同时线程池的有一个致命性问题,程序开发时并不知道将来的并发量是多少,线程池的线程数量无法确定,多了造成资源浪费,少了便是并行处理时间延长.至于如何解决,将会在下面的Task中进行讲解;

Task 任务:

概念:任务代表了一个异步操作;使用任务极大的简化了异步编程;

从本质上将任务就是线程池增强版的Api ;

为什么使用任务实现异步编程???
线程池中的线程数目是固定的,无法应对激增的并发请求;
线程池获取计算结果并不方便;
线程池实现异步处理步骤繁琐;
线程池不适合连续的异步操作;实现起来会造成“死亡嵌套”,降低代码的可阅读性

Task 任务可以使用链式编程实现进一步的异步操作,对线程可以实现动态的添加

任务创建:
1、构造函数创建:

static void Main(string[] args)
{
    Task task = new Task(() =>
    {
        // True 线程池线程
        Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
    });
    task.Start();
    Console.ReadLine();
}

使用工厂模式创建

  Task.Factory.StartNew(() =>
    {
        // True 线程池线程
        Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
    });
    Console.ReadLine();

注意 注意 注意
任务工厂模式下,任务会立即执行,使用构造函数创建需要手动执行

任务默认使用线程池线程,这就是为什么说任务是线程池增强版的Api le

手动不使用线程池线程

static void Main(string[] args)
{
    Task task = new Task(() =>
    {
        // False 不使用线程池
        Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
    }, TaskCreationOptions.LongRunning);
    task.Start();
    Console.ReadLine();
}

获取任务结果
Task;

Task<string> task = new Task<string>(() =>
{
    DoSomething();
    return "此处为执行完成的结果";


});
task.Start();
Console.WriteLine(task.Result);

任务的回调
使用continueWith()

特点 :支持一个Task接多个Continuewith ;
Continue With返回下一代task 下一代可以继续ContinueWith;支持链式编程,增强代码可读性;

 Task<string> task = new Task<string>(() =>
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        return "boy,";
    });
    task.ContinueWith((t) =>
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine(t.Result + "come on.");
    });
    task.Start();
    Console.ReadLine();

Task的线程等待和延续

Wait /WaitAny/WaitAll;
task.Wait() 表示等待task执行完毕,功能类似于thead.Join(); Task.WaitAll(Task[] tasks) 表示只有所有的task都执行完成了再解除阻塞; Task.WaitAny(Task[] tasks) 表示只要有一个task执行完毕就解除阻塞,看一个栗子:

        static void Main(string[] args)
        {
            Task task1 = new Task(() => {
                Thread.Sleep(500);
                Console.WriteLine("线程1执行完毕!");
            });
            task1.Start();
            Task task2 = new Task(() => {
                Thread.Sleep(1000);
                Console.WriteLine("线程2执行完毕!");
            });
            task2.Start();
            //阻塞主线程。task1,task2都执行完毕再执行主线程
       //执行【task1.Wait();task2.Wait();】可以实现相同功能
            Task.WaitAll(new Task[]{ task1,task2});
            Console.WriteLine("主线程执行完毕!");
            Console.ReadKey();
        }

延续任务操作 :
whenAll ,whenAny;

task.WhenAll(Task[] tasks) 表示所有的task都执行完毕后再去执行后续的操作, task.WhenAny(Task[] tasks) 表示任一task执行完毕后就开始执行后续操作;
这里需要注意的一点是 :
使用when不会阻塞主线程;使用when执行后续操作利用的是Continue With()实现 回调方法调用,因而不会阻塞主进程;

Task Factory在任务工厂模式同样可以执行相应的操作;
ContinueWhenAny:等价于Task的WhenAny+ContinueWith

ContinueWhenAll:等价于Task的WhenAll+ContinueWith

1.ContinueWhenAny

Task.Factory.ContinueWhenAny(taskList.ToArray(),m=>{
	Console.WriteLine("")
})

2.ContinueWhenAll

Task.Factory.ContinueWhenAll(taskList.ToArray(),m=>{
	Console.WriteLine("")
})

异步编程关键字Async/Await

async/await是C#5.0引入的一个关键词,其目的是让异步编程边的更加简洁,也是为了顺应异步编程的大趋势。

功能:·

1使用async/await能简单的创建异步方法,异步方法可以防止耗时操作阻塞当前线程。

2使用async/await来构建异步方法,更加简洁。

语法

  1. 方法使用async进行修饰;
  2. 方法内部包含一个或多个 await表达式,表示异步执行的任务;
  3. 方法必须具备三中返回类型之一,void,Task,Task ,其中后两种用于返回对象表示未来完成的工作,调用方法和异步方法可以继续执行;Task 允许使用其返回运算结果进行下一操作;
  4. 异步方法可以使用任何类型参数,ref和out除外
  5. 在异步编程中异步方法的命名规范为Async作为名称后缀以表明方法为异步方法;

注意 注意:如果方法中没有出现await 那么该方法就是同步方法;

WebService

远程接口调用

无关系数据库

Socket

WebScoket

Singlar

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值