如何批量执行for循环?

时间:2014-05-29 05:55:36

标签: python python-2.7 batch-processing

for x in records:
   data = {}
   for y in sObjectName.describe()['fields']
         data[y['name']] = x[y['name']]
   ls.append(adapter.insert_posts(collection, data))

我想执行批量大小为500的代码ls.append(adapter.insert_post(collection,x)),其中x应包含500个数据dicts。我可以使用double for循环和列表创建500个数据dicts的列表,然后插入它。我可以通过以下方式做到这一点,有没有更好的方法呢? :

for x in records:
    for i in xrange(0,len(records)/500):
        for j in xrange(0,500):
            l=[]
            data = {}
            for y in sObjectName.describe()['fields']:
                data[y['name']] = x[y['name']]
                #print data
            #print data
            l.append(data)
        ls.append(adapter.insert_posts(collection, data))

    for i in xrange(0,len(records)%500):
        l=[]
        data = {}
        for y in sObjectName.describe()['fields']:
            data[y['name']] = x[y['name']]
            #print data
        #print data
        l.append(data)
    ls.append(adapter.insert_posts(collection, data))

4 个答案:

答案 0 :(得分:24)

我使用的一般结构如下:

worklist = [...]
batchsize = 500

for i in xrange(0, len(worklist), batchsize):
    batch = worklist[i:i+batchsize] # the result might be shorter than batchsize at the end
    # do stuff with batch

请注意,我们正在使用step的{​​{1}}参数来大大简化批处理。

答案 1 :(得分:7)

如果你正在处理序列,那么@nneonneo的解决方案就像你能得到的那样高效。如果你想要一个适用于任意迭代的解决方案,你可以查看一些itertools recipes。例如石斑鱼:

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return itertools.izip_longest(fillvalue=fillvalue, *args)

我倾向于不使用这个,因为它用None“填充”最后一个组,因此它与其他组的长度相同。我通常定义我自己的变体,它没有这种行为:

def grouper2(iterable, n):
    iterable = iter(iterable)
    while True:
        tup = tuple(itertools.islice(iterable, 0, n))
        if tup:
            yield tup
        else:
            break

这会产生所请求大小的元组。这通常是足够好的,但是,为了一点乐趣,我们可以编写一个生成器,如果我们真的想要...返回正确大小的惰性迭代...

我认为这里的“最佳”解决方案取决于手头的问题 - 特别是原始可迭代中的组和对象的大小以及原始可迭代的类型。一般来说,最后2个食谱的用量较少,因为它们更复杂,很少需要。但是,如果您喜欢冒险并且心情愉快,请继续阅读!


我们需要获得一个惰性迭代而不是元组的唯一真正修改是能够“查看”islice中的下一个值以查看是否有任何内容。在这里我只是看看价值 - 如果它丢失了,StopIteration将被提升,这将停止发电机,就像它正常结束一样。如果它在那里,我用itertools.chain

把它放回去
def grouper3(iterable, n):
    iterable = iter(iterable)
    while True:
        group = itertools.islice(iterable, n)
        item = next(group)  # raises StopIteration if the group doesn't yield anything
        yield itertools.chain((item,), group)

小心,但是如果你完全耗尽每个迭代,那么只有“才能工作”继续移动到下一个。在极端情况下,您不会耗尽任何迭代,例如, list(grouper3(..., n)),你将得到“m”个迭代,它只产生1个项目,而不是n(其中“m”是输入可迭代的“长度”)。这种行为有时可能很有用,但通常不常见。如果我们使用itertools“consume”配方(除collections之外还需要导入itertools),我们也可以解决这个问题:

def grouper4(iterable, n):
    iterable = iter(iterable)
    group = []
    while True:
        collections.deque(group, maxlen=0)  # consume all of the last group
        group = itertools.islice(iterable, n)
        item = next(group)  # raises StopIteration if the group doesn't yield anything
        group = itertools.chain((item,), group)
        yield group

当然,list(grouper4(..., n))将返回空的迭代 - 在next的下一次调用之前未从“组”中提取的任何值(例如,当for循环循环回到开始)永远不会屈服。

答案 2 :(得分:1)

也许是这样的?

l = []
for ii, x in enumerate(records):
    data = {}
    for y in sObjectName.describe()['fields']
        data[y['name']] = x[y['name']]
    l.append(data)
    if not ii % 500:
        ls.append(adapter.insert_posts(collection, l))
        l = []

答案 3 :(得分:1)

我认为这里不涉及一种特殊情况。假设批次大小为100,列表大小为103,以上答案可能会漏掉最后3个元素。

list = [.....] 103 elements
total_size = len(list)
batch_size_count=100

for start_index in range(0, total_size, batch_size_count):
    end_index = total_size if start_index + batch_size_count > total_size else start_index + batch_size_count
    list[start_index:end_index] #Slicing operation

可以将切片列表发送给每个方法调用,以完成所有元素的执行。