异步比同步慢

时间:2014-03-05 17:14:30

标签: c# asynchronous task-parallel-library async-await .net-4.5

我一直在处理异步调用,我发现方法的异步版本运行速度比同步版本慢得多。任何人都可以对我可能遗失的内容发表评论。感谢。

统计

同步方法时间为00:00:23.5673480

异步方法时间为00:01:07.1628415

每次通话返回的记录/条目总数= 19972

以下是我正在运行的代码。

--------------------测试类----------------------

[TestMethod]
public void TestPeoplePerformanceSyncVsAsync()
{
    DateTime start;
    DateTime end;

    start = DateTime.Now;
    for (int i = 0; i < 10; i++)
    {
    using (IPersonRepository repository = kernel.Get<IPersonRepository>())
    {
        IList<IPerson> people1 = repository.GetPeople();
        IList<IPerson> people2 = repository.GetPeople();
    }
    }
    end = DateTime.Now;
    var diff = start - end;
    Console.WriteLine(diff);

    start = DateTime.Now;
    for (int i = 0; i < 10; i++)
    {
    using (IPersonRepository repository = kernel.Get<IPersonRepository>())
    {
        Task<IList<IPerson>> people1 = GetPeopleAsync();
        Task<IList<IPerson>> people2 = GetPeopleAsync();
        Task.WaitAll(new Task[] {people1, people2});
    }
    }
    end = DateTime.Now;
    diff = start - end;
    Console.WriteLine(diff);
}

private async Task<IList<IPerson>> GetPeopleAsync()
{
    using (IPersonRepository repository = kernel.Get<IPersonRepository>())
    {
    return await repository.GetPeopleAsync();
    }
}

-------------------------- Repository -------------------- --------

    public IList<IPerson> GetPeople()
    {
        List<IPerson> people = new List<IPerson>();
        using (PersonContext context = new PersonContext())
        {
            people.AddRange(context.People);
        }
        return people;
    }

    public async Task<IList<IPerson>> GetPeopleAsync()
    {
        List<IPerson> people = new List<IPerson>();
        using (PersonContext context = new PersonContext())
        {
            people.AddRange(await context.People.ToListAsync());
        }
        return people;
    }

2 个答案:

答案 0 :(得分:5)

所以我们在这里找到了一大堆的问题,所以我马上就说这不会是一个详尽的清单。

首先,异步的 point 并不严格来提高性能。在某些情况下,它可以用于提高性能,但这并非必然其目标。例如,它还可以用于保持UI响应。 Paralleization 通常用于提高性能,但并行化和异步性并不相同。在 之上,并行化有一个开销。您花时间创建线程,安排线程,在它们之间同步数据等。并行执行某些操作的好处可能会也可能不会超过此开销。如果没有,同步解决方案可能会更高效。

接下来,您的“异步”示例并非异步“一直向上”。你在循环内的任务上调用WaitAll。为了使示例正确异步,我们希望看到它一直是异步的,直到单个操作,即某种形式的消息循环。

接下来,两者在异步和同步庄园中并不完全相同。他们做不同的事情,这显然会影响绩效:

  • 您的“异步”解决方案会创建3个存储库。您的同步解决方案创建一个这里会有一些开销。
  • GetPeopleAsync获取一个列表,然后从列表中提取所有项目并将它们放入另一个列表中。这是不必要的开销。

然后您的基准测试存在问题:

  • 您正在使用DateTime.Now,它不是为计算操作所需的时间而设计的。例如,它的精度不是特别高。您应该使用StopWatch来计算代码所需的时间。
  • 您没有执行那么多次迭代。这里的变化有很多机会影响结果。
  • 您没有考虑到前几个代码段运行的时间会更长。 JITter需要“热身”。
  • 垃圾收集可能会影响您的时间,即第一次测试中创建的对象最终可能会在第二次测试期间被清理。

答案 1 :(得分:1)

这可能取决于您的数据,或者更确切地说取决于数据量。您没有发布用于运行测试的测试指标,但这是我的经验:

通常当你看到并行算法的性能在你预期改进时会减速时,加载额外的库和产生线程等的开销会降低并行算法的速度并使其看起来像线性/单一 - 线程版本表现更好。

更多数据应显示更好的性能。当加载所有库时,也尝试运行相同的测试两次,以避免负载开销。

如果你没有看到改善,那就严重错误了。

注意:我猜测你正在投票,因为你在OP中发布了比上下文,指标等更多的代码。 IMO,很少有SOers实际上会费心去阅读和理解这么多代码而不能执行它,同时还提供了一些根本没用的指标!

为什么我没有阅读代码:当我看到带有滚动条的代码块以及原始OP中存在的文本类型时,我的大脑说:不要打扰。我想很多,如果不是大多数,可能会这样做。

要尝试的事情:

  • 两个不同的同步时间并不意味着统计上显着的数据。您应该多次运行每个算法(至少5个)以查看您是否遇到异常。如果相同算法的结果差异很大,那么您可能会遇到其他问题,例如带宽限制,服务器负载等问题,而且问题是外部问题。
  • 尝试使用.NET内存性能和/或内存分析器来帮助您追踪问题。
  • 有关更多线索,请参阅@ servy的绝佳答案。他似乎真的花时间更仔细地查看你的代码。
相关问题