加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 为什么额外的异步操作使我的代码比没有进行操作时更快?

发布时间:2020-12-15 22:18:37 所属栏目:百科 来源:网络整理
导读:我正在开发基于短信的游戏(增值服务),其中必须每天向每个用户发送一个问题.有超过500,000个订户,因此性能是一个关键因素.由于每个订户可以是具有不同变量的竞争的差异状态,因此在发送文本消息之前必须为每个订户单独查询数据库.为了获得最佳性能,我使用.Net
我正在开发基于短信的游戏(增值服务),其中必须每天向每个用户发送一个问题.有超过500,000个订户,因此性能是一个关键因素.由于每个订户可以是具有不同变量的竞争的差异状态,因此在发送文本消息之前必须为每个订户单独查询数据库.为了获得最佳性能,我使用.Net任务并行库(TPL)来生成并行线程池线程,并在每个线程中尽可能多地执行异步操作,以便最终发送文本asap.

在描述实际问题之前,需要更多信息来提供代码.

起初,代码中没有异步操作.我只是使用默认任务调度程序将大约500,000个任务安排到Threadpool中,每个任务都将通过例程,阻止所有EF(实体框架)查询并顺序完成其工作.这很好,但还不够快.然后我将所有EF查询更改为Async,结果是速度极佳,但SQL服务器中存在如此多的死锁和超时,大约三分之一的订阅者从未收到过文本!在尝试不同的解决方案之后,我决定在24核服务器上运行超过500,000个任务(至少有24个并发线程池线程)时不要执行太多的异步数据库操作!
我回滚了所有更改(Asycn)期望在每个仍然异步的任务中进行一次Web服务调用.

现在奇怪的情况:

在我的代码中,我有一个名为“isCrossSellActive”的布尔变量.设置变量时,会发生更多数据库操作,并且会发生线程等待的asycn webservice调用.当此变量为false时,将不会发生这些操作,包括异步Web服务调用.设置变量时,代码运行速度比没有变量时快得多!似乎由于某种原因,等待的异步代码(协作线程)使代码更快.

这是代码:

public async Task AutoSendMessages(...)
    {

        //Get list of subscriptions plus some initialization



        LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(numberOfThreads);
        TaskFactory taskFactory = new TaskFactory(lcts);
        List<Task> tasks = new List<Task>();

        //....

        foreach (var sub in subscriptions)
        {
            AutoSendData data = new AutoSendData
            {
                ServiceId = serviceId,MSISDN = sub.subscriber,IsCrossSellActive = bolCrossSellHeader
            };

            tasks.Add(await taskFactory.StartNew(async (x) =>
            {
                await SendQuestion(x);
            },data));
        }

        GC.Collect();

        try
        {
            Task.WaitAll(tasks.ToArray());
        }
        catch (AggregateException ae)
        {
            ae.Handle((ex) =>
            {
                _logRepo.LogException(1,"",ex);
                return true;
            });
        }

        await _autoSendRepo.SetAutoSendingStatusEnd(statusId);
    }

public async Task SendQuestion(object data)
    {
        //extract variables from input parameter

        try
        {
            if (isCrossSellActive)
            {
                int pieceCount = subscriptionRepo.GetSubscriberCarPieces(curSubscription.service,curSubscription.subscriber).Count(c => c.isConfirmed);

                foreach (var rule in csRules)
                {
                    if (rule.Applies) 
                    {
                        if (await HttpClientHelper.GetJsonAsync<bool>(url,rule.TargetServiceBaseAddress))
                        {
                            int noOfAddedPieces = SomeCalculations();

                            if (noOfAddedPieces > 0)
                            {
                            crossSellRepo.SetPromissedPieces(curSubscription.subscriber,curSubscription.service,rule.TargetShortCode,noOfAddedPieces,rule.ExpirationLimitDays);
                            }
                        }
                    }
                }
            }
// The rest of the code. (Some db CRUD)
await SmsClient.SendSoapMessage(subscriber,smsBody);
        }
catch (Exception ex){//...}
}

解决方法

好的,多亏了@usr和他给我的线索,问题终于解决了!
他的评论引起我的注意,期待已经等待的taskFactory.StartNew(…)行,它将新任务顺序添加到“任务”列表中,然后由Task.WaitAll(任务)等待;

起初我在taskFactory.StartNew()之前删除了await关键字,它导致代码处于可怕的故障状态!然后我在taskFactory.StartNew()之前返回await关键字并使用断点调试代码,并且令人惊讶地看到线程在第一个线程到达“SendQuestion”例程内的第一个线程之前一个接一个地运行.当设置“isCrossSellActive”标志时,尽管线程应该执行更多作业,但是先前达到第一个await关键字,从而启用下一个计划任务.但是当它没有设置时,唯一的await关键字是例程的最后一行,所以它最有可能顺序运行到最后.

usr建议在for循环中删除await关键字似乎是正确的但问题是Task.WaitAll()行会在错误的Task列表上等待< Task< void>>而不是任务< void>.我终于使用Task.Run而不是TaskFactory.StartNew,一切都改变了.现在服务运作良好. for循环中的最终代码是:

tasks.Add(Task.Run(async () =>
            {
                await SendQuestion(data);
            }));

问题解决了.
谢谢你们.

附:阅读关于Task.Run的这篇文章以及为什么TaskFactory.StartNew是危险的:http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读