简体   繁体   English

使用async / await来提高性能

[英]Using async/await to improve performance

I currently have a service method that runs a set of "rules" on incoming data. 我目前有一个服务方法,对传入的数据运行一组“规则”。 Some of these rules perform simple checks like validating a Id number, and some go out to databases to lookup information. 其中一些规则执行简单检查,如验证Id号,有些则转到数据库查找信息。 It looks pretty much like this: 它看起来非常像这样:

public void RunRules(ValidationRequest request)
{
    // Each rule returns bool for this example
    var rules = GetRules();

    var results = List<bool>();

    Parallel.ForEach(rules, rule =>
    {
        var result = rule();

        lock(results)
            results.Add(result);
    });

    foreach(var result in results)
    {
        RecordResultInDatabase(result);
    }

    CallNextService(someNewRequest);
}

I think (but am not sure) that I could improve things using async/await . 我认为(但不确定)我可以使用async/await来改进。 My idea is, when one rule finishes it could then call RecordResultInDatabase while other rules are still running. 我的想法是,当一个规则完成后,它可以调用RecordResultInDatabase而其他规则仍在运行。

As a requirement though, I wouldn't want a call to CallNextService to happen until all rules have ran and their results recorded in the database. 但是,作为一项要求,我不希望调用CallNextService ,直到所有规则都运行并将结果记录在数据库中。

Problem is I'm an absolute noob to async/await and I think (but am not sure) that the Task.WaitAll might be what I'm looking for. 问题是我是async/await的绝对Task.WaitAll ,我认为(但不确定) Task.WaitAll可能就是我正在寻找的东西。

I'm very uncertain of how do this, but something like this I'm guessing: 我很不确定这是怎么做的,但我猜是这样的:

List<Task<bool>> ruleTasks = GetRules();
Task.WaitAll(ruleTasks);

// Somehow get the results of the rules and record them in the db???

I don't think async - await will improve performance in your case. 我不认为async - await会提高您的性能。 In short, async - await is useful in two cases: 简而言之, async - await在两种情况下很有用:

  1. To improve responsiveness of GUI applications. 提高GUI应用程序的响应能力。
  2. To improve scalability of server applications. 提高服务器应用程序的可伸缩性。

Neither of those seems to be your case, so there is no reason to use async - await in your code. 这些似乎都不是你的情况,因此没有理由在你的代码中使用async - await

If you want to call RecordResultInDatabase() while requests are being processed, instead of when all of them are done, you can use PLINQ instead of Parallel.ForEach() . 如果要在处理请求时调用RecordResultInDatabase() ,而不是在完成所有请求时,可以使用PLINQ而不是Parallel.ForEach() As another benefit, it will also simplify your code: 另一个好处是,它还可以简化您的代码:

var results = GetRules().AsParallel().Select(rule => rule());

foreach (var result in results)
{
    RecordResultInDatabase(result);
}

You're not after await/async: those are designed to suspend execution of a method in a GUI application while preventing the GUI from freezing, and to improve scalability in server scenarios because it can sometimes avoid using a "thread" for the "await". 你不是在await / async之后:那些被设计为暂停GUI应用程序中的方法的执行,同时防止GUI冻结,并提高服务器场景中的可伸缩性,因为它有时可以避免使用“线程”进行“等待” ”。 Since you don't seem to be waiting for asynchronous operations and this is not a GUI then neither of this applies to you. 由于您似乎没有等待异步操作,并且这不是GUI,因此这两者都不适用于您。

The client calling your service might employ await/async, but that's a different problem. 调用您的服务的客户端可能会使用await / async,但这是一个不同的问题。

What you could look into is Task (the parallel task library). 你可以看到的是Task (并行任务库)。 But only if your tests truly can run in parallel and are substantial enough to be worth it ! 但是,只有当你的测试真正能够并行运行并且足够值得它 For tiny, fast & simple tests running them in parallel will likely hurt performance, not improve. 对于微小,快速和简单的测试并行运行它们可能会损害性能,而不是改善。

Finally, since this runs on a server, you need to take into account concurrent activities: is the server only servicing this request? 最后,由于这在服务器上运行,因此您需要考虑并发活动:服务器是否仅为请求提供服务? Unless that's true you shouldn't use threads at all, keep things single-threaded and clean. 除非这是真的,否则你根本不应该使用线程,保持单线程和干净。 Since all CPU-threads would be tied up in servicing other concurrent requests, running multiple Tasks or a ParallelLoop will only hurt performance, and not just for this request but for every other request that runs at the same time. 由于所有CPU线程都会在处理其他并发请求时受到限制,因此运行多个Tasks或ParallelLoop 只会损害性能,而不仅仅是针对此请求,而是针对同时运行的每个其他请求。 That's because there would be no "free" cores to take your threads yet you do request them. 那是因为没有“免费”核心可以接受你的线程但你确实要求它们。 There's no extra CPU capacity to tap into. 没有额外的CPU容量可供使用。 You just end up doing context-switching (and paying the penalty for that) without getting any benefit. 你最终会在不获得任何好处的情况下进行上下文切换(并为此付出代价)。

As always: test, test, test. 一如既往:测试,测试,测试。

Task class on MSDN: http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx MSDN上的任务类: http//msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM