•   欢迎来到21NN网.
  •   请记住本站网址www.21nn.cn

C#中Thread,Task,Async/Await,IAsyncResult的图文代码详解【C#.Net教程】,C#,Thread,IAsyncResult

摘要: 本文重要引见了C#中Thread,Task,Async/Await,IAsyncResult的相干学问。具有肯定的参考价值,下面随着小编一起来看下吧提及异步,Thread,Task,asyn...
本文重要引见了C#中 Thread,Task,Async/Await,IAsyncResult的相干学问。具有肯定的参考价值,下面随着小编一起来看下吧

提及异步,Thread,Task,async/await,IAsyncResult 这些东西肯定是绕不开的,本日就来顺次聊聊他们

1.线程(Thread)

多线程的意义在于一个应用顺序中,有多个实行部份能够同时实行;关于比较耗时的操纵(比方io,数据库操纵),或许守候相应(如WCF通讯)的操纵,能够零丁开启背景线程来实行,如许主线程就不会壅塞,能够继承往下实行;比及背景线程实行终了,再关照主线程,然后做出对应操纵!

在C#中开启新线程比较简朴

static void Main(string[] args)
{
 Console.WriteLine("主线程最先");
 //IsBackground=true,将其设置为背景线程
 Thread t = new Thread(Run) { IsBackground = true };
 t.Start();
   Console.WriteLine("主线程在做其他的事!");
 //主线程完毕,背景线程会自动完毕,不论有无实行完成
 //Thread.Sleep(300);
 Thread.Sleep(1500);
 Console.WriteLine("主线程完毕");
}
static void Run()
{
 Thread.Sleep(700);
 Console.WriteLine("这是背景线程挪用");
}

实行效果以下图,

能够看到在启动背景线程以后,主线程继承往下实行了,并没有比及背景线程实行完以后。

1.1 线程池

试想一下,如果有大批的使命须要处置惩罚,比方网站背景关于HTTP要求的处置惩罚,那是不是要对每个要求建立一个背景线程呢?明显不合适,这会占用大批内存,而且频仍地建立的历程也会严重影响速率,那怎样办呢?线程池就是为了处理这一题目,把建立的线程存起来,构成一个线程池(内里有多个线程),当要处置惩罚使命时,若线程池中有余暇线程(前一个使命实行完成后,线程不会被接纳,会被设置为余暇状况),则直接挪用线程池中的线程实行(例asp.net处置惩罚机制中的Application对象),

运用事例:

for (int i = 0; i < 10; i++)
{
 ThreadPool.QueueUserWorkItem(m =>
 {
  Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
 });
}
Console.Read();

运转效果:

能够看到,虽然实行了10次,但并没有建立10个线程。

1.2 信号量(Semaphore)

Semaphore担任谐和线程,能够限定对某一资本接见的线程数目

这里对SemaphoreSlim类的用法做一个简朴的事例:

 static SemaphoreSlim semLim = new SemaphoreSlim(3); //3示意最多只能有三个线程同时接见
static void Main(string[] args)
{
 for (int i = 0; i < 10; i++)
 {
  new Thread(SemaphoreTest).Start();
 }
 Console.Read();
}
static void SemaphoreTest()
{
 semLim.Wait();
 Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "最先实行");
 Thread.Sleep(2000);
 Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "实行终了");
 semLim.Release();
}

实行效果以下:

能够看到,刚最先只要三个线程在实行,当一个线程实行终了并开释以后,才会有新的线程来实行要领!

除了SemaphoreSlim类,还能够运用Semaphore类,觉得越发天真,感兴致的话能够搜一下,这里就不做演示了!

2.Task

Task是.NET4.0到场的,跟线程池ThreadPool的功用相似,用Task开启新使命时,会从线程池中挪用线程,而Thread每次实例化都邑建立一个新的线程。

Console.WriteLine("主线程启动");
//Task.Run启动一个线程
//Task启动的是背景线程,要在主线程中守候背景线程实行终了,能够挪用Wait要领
//Task task = Task.Factory.StartNew(() => { Thread.Sleep(1500); Console.WriteLine("task启动"); });
Task task = Task.Run(() => { 
 Thread.Sleep(1500);
 Console.WriteLine("task启动");
});
Thread.Sleep(300);
task.Wait();
Console.WriteLine("主线程完毕");

实行效果以下:

开启新使命的要领:Task.Run()或许Task.Factory.StartNew(),开启的是背景线程

要在主线程中守候背景线程实行终了,能够运用Wait要领(会以同步的体式格局来实行)。不必Wait则会以异步的体式格局来实行。

比较一下Task和Thread:

static void Main(string[] args)
{
 for (int i = 0; i < 5; i++)
 {
  new Thread(Run1).Start();
 }
 for (int i = 0; i < 5; i++)
 {
  Task.Run(() => { Run2(); });
 }
}
static void Run1()
{
 Console.WriteLine("Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}
static void Run2()
{
 Console.WriteLine("Task挪用的Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}

实行效果:

能够看出来,直接用Thread会开启5个线程,用Task(用了线程池)开启了3个!

2.1 Task<TResult>

Task<TResult>就是有返回值的Task,TResult就是返回值范例。

Console.WriteLine("主线程最先");
//返回值范例为string
Task<string> task = Task<string>.Run(() => {
 Thread.Sleep(2000); 
 return Thread.CurrentThread.ManagedThreadId.ToString(); 
});
//会比及task实行终了才会输出;
Console.WriteLine(task.Result);
Console.WriteLine("主线程完毕");

运转效果:

经由过程task.Result能够取到返回值,若取值的时刻,背景线程还没实行完,则会守候其实行终了!

简朴提一下:

Task使命能够经由过程CancellationTokenSource类来作废,觉得用得不多,用法比较简朴,感兴致的话能够搜一下!

3. async/await

async/await是C#5.0中推出的,先上用法:

static void Main(string[] args)
{
 Console.WriteLine("-------主线程启动-------");
 Task<int> task = GetStrLengthAsync();
 Console.WriteLine("主线程继承实行");
 Console.WriteLine("Task返回的值" + task.Result);
 Console.WriteLine("-------主线程完毕-------");
}
static async Task<int> GetStrLengthAsync()
{
 Console.WriteLine("GetStrLengthAsync要领最先实行");
 //此处返回的<string>中的字符串范例,而不是Task<string>
 string str = await GetString();
 Console.WriteLine("GetStrLengthAsync要领实行完毕");
 return str.Length;
}
static Task<string> GetString()
{
   //Console.WriteLine("GetString要领最先实行")
 return Task<string>.Run(() =>
 {
  Thread.Sleep(2000);
  return "GetString的返回值";
 });
}

async用来润饰要领,表明这个要领是异步的,声明的要领的返回范例必需为:void,Task或Task<TResult>。

await必需用来润饰Task或Task<TResult>,而且只能涌如今已用async症结字润饰的异步要领中。通常情况下,async/await成对涌现才有意义,

看看运转效果:

能够看出来,main函数挪用GetStrLengthAsync要领后,在await之前,都是同步实行的,直到碰到await症结字,main函数才返回继承实行。

那末是不是是在碰到await症结字的时刻顺序自动开启了一个背景线程去实行GetString要领呢?

如今把GetString要领中的那行解释加上,运转的效果是:

人人能够看到,在碰到await症结字后,没有继承实行GetStrLengthAsync要领背面的操纵,也没有立时反回到main函数中,而是实行了GetString的第一行,以此能够推断await这里并没有开启新的线程去实行GetString要领,而是以同步的体式格局让GetString要领实行,比及实行到GetString要领中的Task<string>.Run()的时刻才由Task开启了背景线程!

那末await的作用是什么呢?

能够从字面上明白,上面提到task.wait能够让主线程守候背景线程实行终了,await和wait相似,同样是守候,守候Task<string>.Run()最先的背景线程实行终了,差别的是await不会壅塞主线程,只会让GetStrLengthAsync要领停息实行。

那末await是怎样做到的呢?有无开启新线程去守候?

只要两个线程(主线程和Task开启的线程)!至于怎样做到的(我也不知道......>_<),人人有兴致的话研讨下吧!

4.IAsyncResult

IAsyncResult自.NET1.1起就有了,包括可异步操纵的要领的类须要完成它,Task类就完成了该接口

在不借助于Task的情况下怎样完成异步呢?

class Program
{
 static void Main(string[] args)
 {
  Console.WriteLine("主顺序最先--------------------");
  int threadId;
  AsyncDemo ad = new AsyncDemo();
  AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

  IAsyncResult result = caller.BeginInvoke(3000,out threadId, null, null);
  Thread.Sleep(0);
  Console.WriteLine("主线程线程 {0} 正在运转.",Thread.CurrentThread.ManagedThreadId)
  //会壅塞线程,直到背景线程实行终了以后,才会往下实行
  result.AsyncWaitHandle.WaitOne();
  Console.WriteLine("主顺序在做一些事变!!!");
  //猎取异步实行的效果
  string returnValue = caller.EndInvoke(out threadId, result);
  //开释资本
  result.AsyncWaitHandle.Close();
  Console.WriteLine("主顺序完毕--------------------");
  Console.Read();
 }
}
public class AsyncDemo
{
 //供背景线程实行的要领
 public string TestMethod(int callDuration, out int threadId)
 {
  Console.WriteLine("测试要领最先实行.");
  Thread.Sleep(callDuration);
  threadId = Thread.CurrentThread.ManagedThreadId;
  return String.Format("测试要领实行的时候 {0}.", callDuration.ToString());
 }
}
public delegate string AsyncMethodCaller(int callDuration, out int threadId);

症结步骤就是赤色字体的部份,运转效果:

和Task的用法差别不是很大!result.AsyncWaitHandle.WaitOne()就相似Task的Wait。

5.Parallel

末了说一下在轮回中开启多线程的简朴要领:

Stopwatch watch1 = new Stopwatch();
watch1.Start();
for (int i = 1; i <= 10; i++)
{
 Console.Write(i + ",");
 Thread.Sleep(1000);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed);
Stopwatch watch2 = new Stopwatch();
watch2.Start();
//会挪用线程池中的线程
Parallel.For(1, 11, i =>
{
 Console.WriteLine(i + ",线程ID:" + Thread.CurrentThread.ManagedThreadId);
 Thread.Sleep(1000);
});
watch2.Stop();
Console.WriteLine(watch2.Elapsed);

运转效果:

轮回List<T>:

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 6, 7, 8, 9 };
Parallel.ForEach<int>(list, n =>
{
 Console.WriteLine(n);
 Thread.Sleep(1000);
});

实行Action[]数组内里的要领:

Action[] actions = new Action[] { 
 new Action(()=>{
  Console.WriteLine("要领1");
 }),
 new Action(()=>{
  Console.WriteLine("要领2");
 })
};
Parallel.Invoke(actions);

以上就是C#中Thread,Task,Async/Await,IAsyncResult的图文代码详解的细致内容,更多请关注ki4网别的相干文章!

分享到:

发表评论

评论列表

还没有评论,快来说点什么吧~

公众号二维码

微信公众号