【问题标题】:Async operation, i'm doing it wrong... why? [closed]异步操作,我做错了......为什么? [关闭]
【发布时间】:2017-07-09 22:07:11
【问题描述】:

同步代码:

public static void ImportData()
{

    for (var i = 0; i < 40000; i++)
    {
        DoSomething(i)
    }
}

异步代码:

public static void ImportDataAsync()
{
    for (int i = 0; i < 40000; i++)
    {
        await DoSomething(i)
    }
}

为了清楚起见,这是我第一次尝试异步操作。

使用异步代码,我的软件真的很慢,如果我同步运行命令行应用程序的多个实例,速度会快 10 倍。

我的意思是,我不认为 DB 访问和 GetAsync 函数的 try/catch 块会在这两种方法之间造成这种差异,你怎么看?

编辑:我不知道如何改进这个问题,但我会尝试给出答案。

我要问的是“Parallel.Foreach”方法,我正在做的是认为“await”前缀会将当前线程设置为待机创建另一个线程并继续 for 循环,而不是等待什么did 是简单地离开该方法直到等待结果,然后他在 for 循环中的同一点返回并在他等待的地方恢复它。

我只是把事情弄糊涂了,特别是在控制台应用程序中,实际上我没有看到任何使用 await/async 的充分理由。

【问题讨论】:

  • 如果没有可靠地重现问题的良好minimal reproducible example,就无法回答。但是,一些观察:“快速”版本似乎完成了“慢”版本工作的 1/5。这将导致 5 倍的差异。此外,“慢速”版本似乎允许多达 100 个并发操作,这可能会产生大量争用(除非两端都有 100 个 CPU 和非常快的网络)。除此之外,您正在使用“旋转等待”来实现该节流,这意味着您在等待时会 100% 占用一个 CPU 内核,这只会使其他一切变慢。
  • 事实是,如果你的机器上只有两个 CPU 内核,而“慢”版本确实做了 5 倍的工作,并且大部分操作成本是本地计算,那么上述观察将完全解释 10 倍的不同。如果不是,那么...您仍然需要解决问题,以便它包含一个好的minimal reproducible example,以便任何人诊断您的问题。可以说,正确完成异步不会以任何明显的方式影响这种情况下的性能,当然不会有 10 倍的差异。
  • 我们怎么知道你为什么做错了?也许只是因为你不是很好?也许你想问这是怎么回事?
  • 我还在学习,我仍然对异步世界有点困惑,但是我相信使用异步代码的主要目标不是让事情变得更快,而是在以下情况下不阻塞 UI 线程做同步的东西。您可以同时运行数千个 Get 请求,最终,您会遇到一些限制(网络、服务器、线程池等等)。虽然您可能认为并行运行所有内容应该会使事情运行得更快,但实际上可能会产生相反的效果(想想管理所有任务所需的所有工作等......)。

标签: c# asynchronous httpclient


【解决方案1】:

初读时,可能是这个? 20 000 与 100 000 次迭代?

// Sync version
var start = 4000000;
var end = start + 20000;

// Async version
var start = 4000000;
var end = start + 100000

在你的异步方法中我也看到了一些东西:

  1. public static void ImportAsyncData() 应该是public static async Task ImportAsyncData() 让调用者等待你的操作

  2. var slot = gs.GetAsync(c); 我想在这里你想await 进行那个调用:var slot = await gs.GetAsync(c); 这样你就不必使用ContinueWith,因为你的GetAsync 调用正在等待,所以仅当或GetAsync 任务完成时才会执行下一行代码。

  3. 你不应该用这样的“忙等待”来等待:while (requestDid - requestDone &gt; 100);,你正在使用你的 CPU 来等待。在这种情况下,您可以在任务之间使用共享变量来考虑并发性,也许使用一些简单的lock 逻辑。

您可以将它重构为这样的东西,但我不太了解您想要实现什么以及您的问题是什么:-)

public async Task ImportAsyncData()
{
    var gs = new Site();

    int requestDid = 0;
    int requestDone = 0;
    var found = 0;

    var watch = System.Diagnostics.Stopwatch.StartNew();
    var start = 4000000;
    var end = start + 100000

    var cod = "user"

    for (int i = start; i < end; i++)
    {
        var ts = watch.Elapsed;
        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
            ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);

        Console.Title = "R: " + (i - start) + " F: " + found + " EL: " + ts;

        var c = cod + i;

        var user = await gs.GetAsync(c);
        if (user == null)
        {
            requestDone++;
            return;
        }

        using (var db = new Database())
        {
            found++;
            db.InsertUser(user);
        }

        requestDid++;
    }
}

【讨论】:

  • 这不是我看到它真的很慢的总执行时间,我在 for 循环中看到了这一点,当使用同步版本时,他喜欢每秒 5 个请求,在异步一个他每秒执行 1/2 次请求,然后在等待请求完成时冻结,然后重新开始。关于异步方法,我不希望调用者必须等待我的操作,这并不重要。 2.如果我等待请求完成,循环不会停止吗? 3. 你是什么意思?可以举个例子吗?
  • 我认为首先你应该阅读一些文档来体验 Async/Await。该资源可能有用:Doc 1Doc 2Doc 3
猜你喜欢
  • 1970-01-01
  • 2012-11-07
  • 2013-02-08
  • 2014-07-27
  • 1970-01-01
  • 2014-02-16
  • 2018-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多