我应该将我的动作方法转换为异步动作方法吗?

3
我有一个网站,用户可以上传PDF并将其转换为WORD文档。
它运行良好,但有时(每小时5-6次)用户需要等待比通常更长的时间才能进行转换...
我使用ASP.NET MVC,流程如下: - 用户上传文件 -> 获取流并将其转换为Word -> 将Word文件保存为临时文件 -> 返回用户URL
我不确定是否必须将此流程转换为异步?基本上,我的流程现在是顺序的,但我每秒大约有3-5个请求,CPU是双核和4 GB RAM。
而且我知道maxConcurrentRequestsPerCPU为5000;Threads Per Processor Limit的默认值为25;所以这些默认设置应该足够了,对吧?
那么为什么我的Web应用有时候还是会出现“等待”情况?我需要修改默认的IIS设置还是应该将同步方法改为异步进行转换?附注:转换本身需要1秒到40-50秒不等的时间,具体取决于PDF文件的大小。
更新:基本上我不太清楚的是:如果用户上传一个文件并且转换时间很长,那么只有当前请求会因此而“受苦”,对吗?因为下一个请求是独立的,会产生另一个CPU调用和不同的线程,所以这里不应该有等待,对吗?

转换过程是否受到 CPU 的限制?如果是,异步操作无法提高性能。 - usr
CPU 用于转换,而 I/O 用于将结果写入文件... - Cristian Boariu
但是写作并不需要特别长的时间吧? - usr
编写非常快,例如转换需要36秒,而写入0s。 - Cristian Boariu
1个回答

1
这里有几件事情必须清楚地定义。异步方法和流程不是同一件事,至少我理解的不是。
使用Task的异步方法(通常也利用async/await关键字)将按以下方式工作:
1. 执行从线程t1开始,直到遇到await。 2. (潜在的)长时间操作不会在线程t1上执行——有时甚至根本不会在应用程序线程上执行,而是利用IOCP(I/O完成端口)。 3. 线程t1被释放回线程池,并准备为其他请求提供服务(如果需要)。 4. 当(潜在的)长时间操作返回时,会从线程池中取出一个线程(甚至可能是相同的t1,或者很可能是另一个线程),并从上次遇到的最后一个await处恢复其余代码执行。 5. 其余代码执行。
这里有几点需要注意:
a. 客户端在整个过程中被阻塞。线程的最终切换等等只在服务器上发生。 b. 这种方法主要设计用于缓解一种不希望出现的条件,称为“线程饥饿”。它并不旨在加快总客户端等待时间,通常也不会加快进程。
据我所理解,异步流至少在这种情况下意味着,在用户请求转换文档后,客户端(即客户端浏览器)将快速接收到一条响应,其中通知他/她该潜在长时间处理已经在服务器上开始,用户应该耐心等待,并且当前的响应页面可能提供进度反馈。
在您的情况下,我建议采用第二种方法,因为第一种方法根本没有帮助。
当然,这不会很容易。您需要模拟一个队列,需要有一个处理代理和一个清除策略(如果您不想要第二个代理,最可能由同一代理执行)。
这将沿以下线路工作:
a. 终端用户提交文件,Web 服务器接收到它 b. Web 服务器将其放置在队列中并接收作业编号 c. Web 服务器返回用户带有作业编号的响应(假设是带有轮询机制的 HTML 页面,该机制会定期从服务器接收进度) d. 当代理有机会时(即完成其他工作时),代理将开始处理文档并在通用位置更新其状态,以供 Web 服务器获取此信息 e. Web 服务器将从 HTML 响应中接收关于作业状态的调用,并发现作业已完成,并提供下载链接或直接开始下载。
这可以以某些方式进行改进:
  1. 可以使用WebSockets或长轮询(例如SignalR同时支持两者),代替客户端轮询服务器。
  2. 如果硬件配置合理,可以使用多个处理代理程序代替一个处理代理程序。

队列可以用简单的关系型数据库(RDBMS)实现,Remus Rușanu有一篇很好的文章介绍了这个方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接