0

我有一个包含数千个元素的集合,我做一个 for 循环来一次处理 100 个元素,然后上传它们并暂停 5 秒

while (EntriesList.Count > 0)
            {
                service.InsertEntries(EntriesList.Take(100).ToList<Entry>());
                System.Threading.Thread.Sleep(5000);
            }

service.InsertEntries以 aList<Entry>作为参数,还有更好的方法来实现这样的事情吗?

通常我会使用带有%运算符和临时列表的 for 循环,上面是否相同?

4

5 回答 5

3

这将一次又一次地插入前 100 个条目。

跟踪您的位置并使用 useSkip前进:

int current = 0;
int batchSize = 100;

while (current < EntriesList.Count)
{
    service.InsertEntries(EntriesList.Skip(current).Take(batchSize).ToList());
    current += batchSize;
    System.Threading.Thread.Sleep(5000);
}
于 2013-11-06T12:25:24.287 回答
2

对于这种事情你应该写一个Chunkify扩展方法。你可以从Marc 那里得到一个很好的例子。但是由于这个问题,它总是返回一个具有固定大小的数组,并且可能是空条目。

所以也许这个实现更符合您的要求:

/// <summary>
/// Divides an enumeration into smaller (same-sized) chunks.
/// </summary>
/// <typeparam name="T">The type of the elements within the sequence.</typeparam>
/// <param name="source">The sequence which should be breaked into chunks.</param>
/// <param name="size">The size of each chunk.</param>
/// <returns>An IEnumerable&lt;T&gt; that contains an IEnumerable&lt;T&gt; for each chunk.</returns>
public static IEnumerable<IEnumerable<T>> Chunkify<T>(this IEnumerable<T> source, int size)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }

    if (size < 1)
    {
        throw new ArgumentOutOfRangeException("size");
    }

    return ChunkifyImpl(source, size);
}

private static IEnumerable<IEnumerable<T>> ChunkifyImpl<T>(IEnumerable<T> source, int size)
{
    using (var iter = source.GetEnumerator())
    {
        while (iter.MoveNext())
        {
            var chunk = new List<T>(size);
            chunk.Add(iter.Current);

            for (int i = 1; i < size && iter.MoveNext(); i++)
            {
                chunk.Add(iter.Current);
            }

            yield return chunk;
        }
    }
}

现在您可以按如下方式使用此扩展:

foreach(var chunk in EntriesList.Chunkify(100))
{
    service.InsertEntries(chunk);
    Thread.Sleep(5000);
}
于 2013-11-06T12:32:21.997 回答
2

EntriesList.Take(100).ToList() 将创建一个包含 100 个条目的新列表,您不会从 EntriesList 中删除这 100 个条目。

您可以执行以下操作:

List<TYPE> objectsforupload = EntriesList.ToList();
while (objectsforupload.Count > 0)
{
        List<TYPE> uploadlist = objectsforupload.Take(100).ToList();
        objectsforupload = objectsforupload.Where(x => !uploadlist.Contains(x)).ToList();
        service.InsertEntries(objectsforupload);
        System.Threading.Thread.Sleep(5000);
}
于 2013-11-06T12:24:11.667 回答
2

之后调用这个.Take()

EntriesList.RemoveRange(0, Math.Min(EntriesList.Count, 100));

它将删除前 100 个元素。

编辑:更完整的例子:

while (EntriesList.Count > 0)
{
    var poppedEntries = EntriesList.Take(100).ToList<Entry>();
    EntriesList.RemoveRange(0, poppedEntries.Count);
    service.InsertEntries(poppedEntries);
    System.Threading.Thread.Sleep(5000);
}
于 2013-11-06T12:26:10.550 回答
1

就目前而言,您的代码不起作用,您还应该跳过相同的数量并且

        while (entries.Count > 0)
        {
            service.InsertEntries(entries.Take(100).ToList<Entry>());
            entries = entries.Skip(100);
            System.Threading.Thread.Sleep(5000);
        }

但是,这表现非常糟糕。从 Skip() 返回的 IEnumable<> 每次调用都会增加开销。

因此,对于这种情况,最好的建议是使用 for 循环。

于 2013-11-06T12:28:12.233 回答