多处理显示多个进度条

时间:2018-02-03 19:21:12

标签: python python-3.x multiprocessing python-3.6 tqdm

对于我的程序,我有一个将随机整数写入.CSV文件的文件。

from __future__ import absolute_import, division, print_function
from numpy.random import randint as randrange
import os, argparse, time
from tqdm import tqdm

def write_to_csv(filename, *args, newline = True):
    write_string = ''
    for arg in args:
        if type(arg) == list:
            for i in arg:
                write_string += str(i) + ','
        else:
            write_string += str(arg) + ','
    if newline:
        write_string = write_string.rstrip(',') + '\n'
    else:
        write_string = write_string.rstrip(',')
    with open(filename+'.csv', 'a') as file:
        file.write(write_string)

def move_dir(dirname, parent = False):
    if not parent:
        dirname = str(dirname)
        exists = os.path.isfile(dirname)
        try:
            os.mkdir(dirname)
            os.chdir(dirname)
        except FileExistsError:
            os.chdir(dirname)
    else:
        os.chdir("..")

def calculate_probability(odds, exitmode = False, low_cpu = 0):
    try:
        file_count = 0
        move_dir('Probability')
        move_dir(str(odds))
        d = {}
        writelist = []
        percentlist = []
        for i in tqdm(range(odds)):
            d[str(i)] = 0
            writelist.append(f'Times {i}')
            percentlist.append(f'Percent {i}')
        while True:
            if os.path.isfile(str(file_count)+'.csv'):
                file_count += 1
            else:
                break
        filename = str(file_count)
        write_to_csv(filename, 'Number', 'Value')
        rep = 500 * odds
        if rep > 10000:
            rep = 10000
        for i in tqdm(range(rep)):
            ran = randrange(odds)
            ran = int(ran)
            d[str(ran)] += 1
            if i == 999:
                write_to_csv(filename, i, ran+1, newline = False)
            else:
                write_to_csv(filename, i, ran+1)
            if low_cpu:
                time.sleep(0.01*float(low_cpu))
        writelist2 = []
        percentlist2 = []
        for i in tqdm(range(odds)):
            val = d[str(i)]
            writelist2.append(val)
            percentlist2.append(round(((val/rep)*100), 2))
        if os.path.isfile('runs.csv'):
            write_to_csv('runs', file_count, writelist2, percentlist2)
        else:
            write_to_csv('runs', 'Run #', writelist, percentlist)
            write_to_csv('runs', file_count, writelist2, percentlist2)
        if exitmode:
            exit()
    except(KeyboardInterrupt, SystemExit):
        if exitmode:
            os.remove(str(file_count)+'.csv')
            exit()
        else:
            try:
                os.system('cls')
                print('User/program interrupted, lauching shutdown mode...')
                os.remove(str(file_count)+'.csv')
                print('Finilizaing current trial...')
                os.chdir("..")
                os.chdir("..")
            except FileNotFoundError:
                exit()
            calculate_probability(odds, exitmode = True)

我也有多次重复系统。

def run_tests(times, odds, low_cpu = 0, shutdown = False):
    for i in tqdm(range(times)):
        calculate_probability(odds, low_cpu = low_cpu)
        os.chdir("..")
        os.chdir("..")
    if shutdown:
        os.system('shutdown /S /F /T 0 /hybrid')

然而,如果我要像30条小道跑,那将需要永远。所以我决定使用多处理模块来加速这个过程。因为每次运行都需要在最后写入同一个文件,所以我必须收集数据并在进程结束后写入它们。

def calculate_probability(odds, low_cpu = 0):
    try:
        file_count = 0
        move_dir('Probability')
        move_dir(str(odds))
        d = {}
        writelist = []
        percentlist = []
        for i in tqdm(range(odds)):
            d[str(i)] = 0
            writelist.append(f'Times {i}')
            percentlist.append(f'Percent {i}')
        while True:
            if os.path.isfile(str(file_count)+'.csv'):
                file_count += 1
            else:
                break
        filename = str(file_count)
        write_to_csv(filename, 'Number', 'Value')
        rep = 500 * odds
        if rep > 10000:
            rep = 10000
        for i in range(rep):
            ran = randrange(odds)
            ran = int(ran)
            d[str(ran)] += 1
            if i == 999:
                write_to_csv(filename, i, ran+1, newline = False)
            else:
                write_to_csv(filename, i, ran+1)
            if low_cpu:
                time.sleep(0.01*float(low_cpu))
        writelist2 = []
        percentlist2 = []
        for i in range(odds):
            val = d[str(i)]
            writelist2.append(val)
            percentlist2.append(round(((val/rep)*100), 2))
        return (writelist, percentlist, writelist2, percentlist2)
    except(KeyboardInterrupt, SystemExit):
        try:
            os.remove(str(file_count)+'.csv')
        finally:
            exit()

def worker(odds, returndict, num, low_cpu = 0):
    returndict[f'write{num}'] = calculate_probability(odds, low_cpu = low_cpu)
    os.chdir("..")
    os.chdir("..")
    os.system('cls')

def run_tests(times, odds, low_cpu = 0, shutdown = False):
    print('Starting...')
    manager = Manager()
    return_dict = manager.dict()
    job_list = []
    for i in range(times):
        p = Process(target=worker, args=(odds,return_dict,i), kwargs = {'low_cpu' : low_cpu})
        job_list.append(p)
        p.start()

    try:
        for proc in job_list:
            proc.join()
    except KeyboardInterrupt:
        print('User quit program...')
        time.sleep(5)
        for proc in job_list:
            proc.join()
        exit()
    else:
        move_dir('Probability')
        move_dir(str(odds))
        if not os.path.isfile('runs.csv'):
            write_to_csv('runs', return_dict.values()[0][0], return_dict.values()[0][1])
        for value in return_dict.values():
            write_to_csv('runs', value[2], value[3])
        print('Done!')
    finally:
        if shutdown:
            os.system('shutdown /S /F /T 0 /hybrid')

然而,当我运行这个新代码时,有一个进度条,每个进程都会覆盖该条,因此条形图闪烁着随机数字,使条形图变得有用。我希望有一堆条形图,每个进程一个,每次更新而不会中断其他进程。酒吧无需订购;我只需要了解每个流程执行任务的速度。

1 个答案:

答案 0 :(得分:0)

STDOUT只是一个流,并且所有进程都附加到同一个进程,所以没有直接的方法告诉它在不同的行上打印不同进程的输出。

实现这一目标的最简单方法可能是建立一个单独的流程,负责汇总所有其他流程的状态并报告结果。您可以使用multiprocessing.Queue将数据从工作线程传递到状态线程,然后状态线程可以将状态打印到stdout。如果你想要一堆进度条,你必须在格式化方面获得一些创意(基本上同时更新所有进度条并以相同的顺序打印它们,使它们看起来堆叠起来)。 / p>