七天学会ASP.NET MVC (6) -- 线程问题
本帖最后由 断天涯大虾 于 2016-7-28 14:17 编辑在上一期的七天学会 ASP.NET MVC 中,小编为大家讲解了 MVC 的用户角色管理。
今天,来为大家讲解 MVC 开发中最常遇到的线程问题。
正如我们知道的,程序中事件都是由线程执行的,请求事件也是。
Asp.net framework 维护线程池,每次当请求发送到 webserver 时,会从线程池中分配空闲的线程处理此请求,这种线程被称为 worker 线程。
当请求处理完成,该线程无法服务其他请求时,worker 线程会被阻塞。现在我们来了解什么是线程饥饿,如果一个应用程序接收到很多请求,且处理每个请求都非常耗时。在这种情况下,我们就必须指定一个点来结束请求,当有新的请求进入状态时,没有 worker 线程可使用,这种现象称为线程饥饿。
在我们的示例程序中只包含2个员工记录,而在实际使用情况下,会包含成千上万的记录,这就意味着将耗费大量的时间来处理请求。这种情况就可能导致线程饥饿.
线程饥饿的解决方法:
截至现在我们讨论的请求类型都是同步请求。如果使用异步请求来代替同步请求,那么线程饥饿的问题就得到解决了。
1.异步请求的情况下,会分配 worker 线程来服务请求。
2.worker 线程初始化异步操作,并返回到线程池服务其他请求。异步操作可使用 CLR 线程来继续执行。
3.存在的问题就是,CLR 线程无法返回响应,一旦它完成了异步操作,它会通知 Asp.net。
4.Webserver 再次获取一个 worker 线程来处理剩余的请求,并返回响应。
上述使用场景中,会获取两次 worker 线程,这两次获取的线程可能相同,也可能会不同。
文件读取是I/O操作,不需要使用 worker 线程处理。因此最好将同步请求转换为异步。
以下是实现将同步 Action 方法转换为异步 Action,将同步请求转换为异步请求的方法。
1. 创建异步控制器
在控制器中将基类 UploadController 修改为 AsynController。
{
public class BulkUploadController : AsyncController
{
2. 转换同步Action方法该功能通过两个关键字就可实现:“async “和” await”
public async Task Upload(FileUploadViewModel model)
{int t1 = Thread.CurrentThread.ManagedThreadId;List employees = await Task.Factory.StartNew<list>(() => GetEmployees(model));int t2 = Thread.CurrentThread.ManagedThreadId;
EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
bal.UploadEmployees(employees);
return RedirectToAction("Index", "Employee");
}
在 action 方法的开始或结束处,使用变量存储线程ID。
理一下思路:
1.当上传按钮被点击时,新请求会被发送到服务器。
2.Webserver 从线程池中产生 Worker 线程 ,并分配给服务器请求。
3.worker 线程会使 Action 方法执行
4.Worker 方法在 Task.Factory.StartNew 方法的辅助下,开启异步操作
5.使用 async 关键字将 Action 方法标记为异步方法,由此会保证异步操作一旦开启,Worker 线程就会释放。
6.使用 await 关键字也可标记异步操作,能够保证异步操作完成时才能够继续执行下面的代码。
一旦异步操作在 Action 方法中完成执行,必须执行 worker 线程。因此 webserver 将会新建一个空闲 worker 线程,并用来服务剩下的请求,提供响应。3. 测试运行
运行应用程序,并跳转到 BulkUpload 页面。会在代码中显示断点,输入样本文件,点击上传。
如图所示,在项目启动或关闭时有的线程ID是不同的。以上就是实现将同步 Action 方法转换为异步 Action 的方法。
后续还会更新 “七天学会 ASP.NET MVC” 的其它篇章,敬请期待。
页:
[1]