将克隆添加到列表很慢

时间:2018-09-26 10:48:26

标签: c# list performance object clone

我正在尝试加速循环,该循环正在克隆 2_500_000 对象。 克隆本身整个循环要花费 800毫秒,但是当我将它们添加到列表中时,它要花费 3秒。.

List<T> list = new List<T>();

Stopwatch sw = new Stopwatch();
sw.Start();

foreach(T entity in listSource)
{
    T entityCloned = GetEntityClone(entity); // Taking 800ms totally

    if (entityCloned != null)
        list.Add(entityCloned);
}

sw.Stop();

您能帮我找出为什么这些Add花费这么多时间吗?

3 个答案:

答案 0 :(得分:2)

不幸的是,循环遍历许多事物并进行深度复制需要花费时间。我认为3秒钟不一定是花费不合理的时间。

但是您可以潜在地提高速度。

首先,如果您事先知道结果列表需要保留多少个项目,则可以set the internal capacity beforehand以防止调整列表大小。调整大小是一项昂贵的活动,必要时可以避免。可以通过手动更改列表的容量属性或通过将容量作为constructor argument for the list传递来实现。

一旦分配了容量,应将the complexity添加到列表中O(1),而无需重新分配(这是O(n)复杂性任务see this answer) 。在这种情况下,添加到列表中不太可能成为瓶颈。

您还可以从要复制的初始列表中删除空值,从而无需每次都要评估的if语句。使用linq

var noNulls = listSource.where(o => o != null)

答案 1 :(得分:0)

我使用数组而不是列表节省了一些时间(大约33%):

MyObject类修饰:

public class MyObject
{
    public int Id { get; set; }
    public bool Flag { get; set; }

    public static MyObject GetEntityClone(MyObject obj)
    {
        if (obj == null) return null;

        var newObj = new MyObject()
        {
            Id = obj.Id,
            Flag = obj.Flag
        };

        return newObj;
    }
}

代码:

var sourceList = new List<MyObject>();

// let's mock the source data, every 27th element will be null
for (int i = 0; i < 2500000; ++i)
{
    if (i % 27 != 0)
        sourceList.Add(new MyObject { Id = i, Flag = (i % 2 == 0) });
}

var destArray = new MyObject[2500000];

Stopwatch sw = new Stopwatch();
sw.Start();
Console.WriteLine(sw.ElapsedMilliseconds);

var currentElement = 0;
for (int i = 0; i < sourceList.Count; ++i)
{
    MyObject entityCloned = MyObject.GetEntityClone(sourceList[i]);

    if (entityCloned != null)
        destArray[currentElement++] = entityCloned;
}

var result = new MyObject[currentElement];
Array.Copy(destArray, 0, result, 0, currentElement);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

答案 2 :(得分:0)

尝试以下操作并行进行:

        var message = new MimeMessage ();
        message.From.Add (new MailboxAddress ("Joey", "joey@friends.com"));
        message.To.Add (new MailboxAddress ("Alice", "alice@wonderland.com"));
        message.Subject = "How you doin?";

        var builder = new BodyBuilder ();

        // Set the plain-text version of the message text
        builder.TextBody = @"Hey Alice,... ";

        // We may also want to attach a calendar event for Monica's party...
        builder.Attachments.Add (@"C:\Users\Joey\Documents\party.ics");

        // Now we just need to set the message body and we're done
        message.Body = builder.ToMessageBody ();