【发布时间】:2018-10-20 06:06:27
【问题描述】:
我正在做一个包含以下详细信息的项目:
- 不涉及 IIS 或其他第 3 方网络服务器
- .NET 4.5 Windows 应用程序,充当“服务器”
- 服务器启动多个 WCF Web 服务,它们都是自托管的
- 网络服务可供多个用户访问
以下是众多 Web 服务方法之一的最简单示例:
public async Task<int> Count()
{
int result = 0;
//There is nothing to await here, so I use Task.Run
await Task.Run(() =>
{
using (IDB ctx = new DB())
{
result = ctx.Customers.All.Count();
}
//Here could happen a lot more
//System.Threading.Thread.Sleep(10000);
}).ConfigureAwait(false);
return result;
}
如您所见,我正在使用 Task.Run 访问一些数据,因为没有一个存储库接口提供异步方法。我不能等待任何事情。如果我想做“真正的异步”,我将不得不重写完整的存储库接口。
如果我不使用 Task.Run,服务器将阻止所有其他传入请求。
我的 2 个问题是:
在这种情况下使用 Task.Run 有什么问题吗?
即使它工作正常并且可能没有完全错误,是否有更好、更专业的解决方案来在异步方法中调用同步代码?
我读到这个问题的最初原因是,在异步方法中使用 Task.Run 是“假异步”。 (我认为 Task.Run 会启动一个新线程,而 "real async" 代码不会)
我回答了我自己的问题,请参阅下面的答案。我希望它可以帮助其他人。
【问题讨论】:
-
so public
async Task<int> Count()?是 WCF 公开的 OperationContract 吗? -
This 是一篇很好的文章,解释了为什么这不是一个好主意。显然它可以像你展示的那样工作。缺点是它确实无法利用异步增加的可扩展性,因为它仍然大量使用线程,这在服务器场景中可能有很高的需求。但是,您确实提到了服务器阻止其他请求,这涉及到异步的第二个用例,即卸载工作。在这种情况下,这样做会很有用。
-
@TheGeneral - 是的,这是自托管 Web 服务公开的功能。
-
@mike z - 这就是我使用 Task.Run 的原因。如果存在长时间运行的同步方法,则所有传入流量都会被阻止。
-
如果您无法更改界面,您可以在方法中添加 await Task.Delay(1) 而不是使用 Task.Run。但值得一提的是,所有使该方法看起来异步的解决方案并不专业。
标签: c# web-services asynchronous server task