替换嵌套的foreach以提高性能

时间:2014-05-20 11:26:28

标签: c# performance linq

我有以下代码需要更长时间才能执行。有没有替代方法,我可以使用LINQ或其他任何方式替换代码以提高性能?

var usedLists = new HashSet<long>();

foreach (var test in Tests)
{
    var requiredLists = this.GetLists(test.test, selectedTag);

    foreach (var List in requiredLists)
    {   
        if (!usedLists.Contains(List.Id))
        {
            usedLists.Add(List.Id);
            var toRecipients = List.RecepientsTo;
            var ccRecipients = List.RecipientsCC;
            var bccRecipients = List.RecipientsBCC;
            var replyTo = new List<string>() { List.ReplyTo };
            var mailMode = isPreviewMode ? MailMode.Display : MailMode.Drafts;
            OutlookModel.Instance.CreateEmail(toRecipients, ccRecipients, bccRecipients, this.Draft, mailMode, replyTo);
        }
    }
}

4 个答案:

答案 0 :(得分:1)

可以使用BackgroundWorker class或类似的东西来完成。 一个非常粗略的大纲是将创建电子邮件参数包装到一个单独的类中,然后在循环继续处理列表时异步启动后台任务。

修改 Task class也可能有用。这假设CreateEmail函数是一直占用的函数。如果这是一直在进行的循环,那么走这条路是没有意义的。

修改 查看算法的复杂性,GetLists()调用在O(n)时间运行,但CreateEmail()调用在O(n ^ 2)时间运行,因此 - 所有其他条件相同 - 包含CreateEmail的代码块( )呼叫将是优先考虑的更好的候选者。

答案 1 :(得分:1)

假设GetList的结果与CreateEmail调用相比足够大/慢,跳过contains-add hashset比较会加快速度。尝试调用Distinct([Your ListComparer])或GroupBy():

var requiredLists = 
    Tests.SelectMany(test => this.GetLists(test.test, selectedTag))
         .Distinct([Your ListComparer]);
// or 
var requiredLists = 
    Tests.SelectMany(test => this.GetLists(test.test, selectedTag))
         .GroupBy(x => x.Id).SelectMany(x => x.First());

foreach (var List in requiredLists)
{   
    // (...)
    OutlookModel.Instance.CreateEmail(toRecipients, ccRecipients, bccRecipients, this.Draft, mailMode, replyTo);
}

您也可以尝试使用PLINQ来加快速度,但我认为您可能会遇到CreateEmail调用问题,因为它可能是COM对象,因此多线程会很麻烦。如果GetList足够慢以至于值得多线程开销,那么您可以在创建requiredLists时在第一次调用中对其进行试验。

答案 2 :(得分:1)

你到底做了什么? 看着

foreach (var test in Tests)
{
    var requiredLists = this.GetLists(test.test, selectedTag);
    foreach (var List in requiredLists)
    {   
        if (!usedLists.Contains(List.Id))

在我看来,你试图获得唯一的“列表”(所有那些“var”我无法分辨实际类型)。所以你实际上可以用一个新函数替换它(由你编写)并执行

var uniqueLists = this.GetUniqueLists(Tests, selectedTag);

最后致电

this.Sendmails(uniqueLists);

将通过该列表进行迭代并发送邮件。

如果这样可以加速代码,则严重依赖于底层的GetLists / GetUniqueLists函数。

但无论如何,它会使你的代码取得很大的进步:它变得可读和可测试。

答案 3 :(得分:0)

  • 每个foreach循环都会创建一个Enumerator对象,因此使用常规的for循环可能会加快一点,但这可能是一个非常小的改进。
  • 像stormenet所说,CreateEmail功能可能是瓶颈。您可能希望将其设为异步。