Python多进程处理数据配合tqdm进度条,全局资源处理

预处理数据的时候使用多进程可以大大减少程序运行时间。

上代码

with Pool(15)as proc:
    results = list(
        tqdm(
            proc.imap(convert_one,files,
                     ),
            total=len(files)
        ))
results = list(chain.from_iterable(results))

解释:files是传入的一个list,里边的每一个元素都需要进行convert_one操作,如果返回的是一个单独元素的话,results就直接得到的是一个一维list,但是上边的代码是具体业务的,convert_one返回的是一个list,则得到的是一个二维list: [[item,item item], [item item item] …] , 最后使用了chain.from_iterable() 转换为 [item , item , item …]形式的一维list。

使用imap而不使用map, 是因为可以提前返回值给tqdm,具体差异建议百度。

如果convert_one 需要一些固定的参数,那么可以使用偏函数,实例:

from functools import partial
with Pool(threads,initializer=squad_convert_example_to_features_init, initargs=(tokenizer,)) as p:
        annotate_ = partial(      #构造偏函数,第一个是原函数,后边是传入的固定参数
            squad_convert_one_example_to_features,
            max_seq_length=max_seq_length,
            doc_stride=doc_stride,
            max_query_length=max_query_length,
            is_training=is_training,
        )
        features = list(
            tqdm(
                p.imap(annotate_, examples, chunksize=32),
                total=len(examples),
                desc="convert squad examples to features",
            )
        )

如果是要传入随机变化的参数,比如files 列表还有一个对应的files2 列表,那么可以考虑zip一下。

对于一些可能会竞争到的资源比如上边代码的tokenizer,需要使用那个init函数把tokenizer给global,不然十几个进程使用一个tokenizer,根本跑不动,具体为什么要使用一个函数,我也不清楚。initargs=(tokenizer,)不要写错,传入的需要是一个iterable的参数。在convert_one里边,不需要tokenizer的传入,直接使用global的。其他只是个数值传入的则不需要,直接在偏函数里写就是了。

def squad_convert_example_to_features_init(tokenizer_for_convert):
    global tokenizer
    tokenizer = tokenizer_for_convert
def squad_convert_one_example_to_features_init(example):
	blabla...
	xx = tokenizer.encode('haha')

参考:HuggingFace的transformers仓库

Contact me : jianshu[AT]std.uestc.edu.cn

你可能感兴趣的:(Python多进程处理数据配合tqdm进度条,全局资源处理)