C#Thread、Task、Async/Await

Thread(线程)

Thread t = new Thread(Run);
t.Start();

问:每个请求过来都创建一个线程?

答:不合适,大量占用内存,并且需要自己维护各个线程,麻烦!于是有了线程池=用于统一调度管理线程。

ThreadPool(线程池)

ThreadPool.QueueUserWorkItem(m => { Run(); });

线程池有会将已创建且空闲线程重复利用起来,10个请求也可能重复使用3个线程即可高效完成。

问:线程池是根据请求随意产生并分配线程数量的,如何控制?

答:使用信号量控制。

Semaphore(信号量)

Semaphore负责协调线程,可以限制对某一资源访问的线程数量。

SemaphoreSlim semLim = new SemaphoreSlim(3); //3表示最多只能有三个线程同时访问
for (int i = 0; i < 10; i++)
{
    new Thread(Run).Start();
}
public void Run()
{
   semLim.Wait();
   //todo...
   semLim.Release();
}

结果:至多只有3个线程同时在跑。


 

Task(线程)

Task是.NET4.0加入的,跟线程池ThreadPool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread每次实例化都会创建一个新的线程。

调用方法如下:

1、Task.Run()

2、Task.Factory.StartNew()

问:一个方法有10个步骤,第1步开启线程执行,继续执行2-9步,第10步需要等待第1步的完成才能执行,如何做到?

答:在第10步之前使用wait方法即可。

问:Thread和Task区别?

答:Thread就是跟线程打交道,Task是基于ThreadPool之上的跟线程池打交道,所以task优于thread,能充分利用空闲的线程继续干活以节省开支。

Task<TResult>

普通版:

Task task = Task.Run(() => {
    //todo...
});
带返回值版:
Task<string> task = Task<string>.Run(() => {
    //todo...
    return "优秀"; 
});
问:如何取线程返回值?
答:task.Result,需要注意的是这个是需要线程等待的,所以也要考虑线程阻塞问题。

Async/Await

async/await是C#5.0中推出的,其实就是基于task的语法糖。

他们是成对出现的!!

1.一个带返回值的异步方法。

private Task<string> GetString()
{
    return Task<string>.Run(() =>
    {
        Thread.Sleep(2000);
        return "优秀";
    });
}
2.成对标识式的调用异步方法
public async Task<int> GetStrLengthAsync()
{
    //此处返回的string中的字符串类型,而不是Task<string>
    string str = await GetString();
    return str.Length;
}
3.主线程中直接调用此标识方法
public void Main(string[] args)
{
    Task<int> task = GetStrLengthAsync();
}


Parallel

Parallel同样也是基于task,很好的解决循环体内的异步问题!

可以参考我之前的一篇博客:http://www.camelcat.com/2019/1126.html

需要注意的:循环体内如果需要对同一个对象进行写操作,一定要使用线程安全的方式;要么加锁,要么使用天然线程安全的数据结构(比如ConcurrentDictionary)。

3



微信扫一扫

微信扫一扫

微信扫一扫,分享到朋友圈

C#Thread、Task、Async/Await
嘿!有什么能帮到您的吗?
返回顶部

显示

忘记密码?

显示

显示

获取验证码

Close