Python数据生成脚本会随着时间而变慢

时间:2019-07-07 04:30:20

标签: python multithreading performance graphviz data-generation

编辑1: 正如fizzybear指出的那样,看来我的内存使用量正在稳步增长,但是我不能说为什么,任何想法都会受到赞赏。

我正在运行一个脚本,该脚本使用staticfg库从python程序(大约150,000个程序)生成大量控制流图。我的代码只是循环遍历每个程序的文件位置,并生成相应的控制流程图。

从经常更新的进度栏中,我可以看到,当脚本开始运行时,它可以在几秒钟内轻松生成约1000个CFG,但是运行半小时,一分钟之内几乎无法生成100个CFG。

为了加快速度,我使用python的多处理map()函数实现了多线程,但这还不够用。

此外,(在所有内核中)CPU利用率在脚本开始时高达80-90%,但在运行几分钟后降至30-40%。

我曾尝试在Windows 10和Ubuntu 18.04上运行它,但两者都减速到几乎无法忍受的速度。

构建控制流图的代码

from staticfg import CFGBuilder

def process_set():
    content = get_file_paths()
    iterate(build_cfg, ERROR_LOG_FILE, content)


def build_cfg(file_path):
    cfg = CFGBuilder().build_from_file(os.path.basename(file_path), os.path.join(DATA_PATH, file_path))
    cfg.build_visual(get_output_data_path(file_path), format='dot', calls=False, show=False)
    os.remove(get_output_data_path(file_path))  # Delete the other weird file created

用于运行cfg建筑物的代码

from threading import Lock
from multiprocessing.dummy import Pool as ThreadPool
import multiprocessing

def iterate(task, error_file_path, content):
    progress_bar = ProgressBar(0, content.__len__(), prefix='Progress:', suffix='Complete')
    progress_bar.print_progress_bar()

    error_file_lock = Lock()
    increment_work_lock = Lock()
    increment_errors_lock = Lock()

    def an_iteration(file):
        try:
            task(file)
        except Exception as e:
            with increment_errors_lock:
                progress_bar.increment_errors()
            with error_file_lock:
                handle_exception(error_file_path, file, 'Error in doing thing', e)
        finally:
            with increment_work_lock:
                progress_bar.increment_work()
                progress_bar.print_progress_bar()

    pool = multiprocessing.dummy.Pool(multiprocessing.cpu_count())
    pool.map(an_iteration, content)

错误处理代码

def handle_exception(error_log_file_path, file_path, message, stacktrace):
    with open(error_log_file_path, 'a+', encoding='utf8') as f:
        f.write('\r{},{},{},{}\n'.format(str(datetime.datetime.now()), message, file_path, stacktrace))

据我所知(?),没有对象的大小不断增加,某处的查找时间也没有增加,所以我对为什么脚本速度变慢感到有些困惑。任何帮助将不胜感激。

我也很确定,不是因为争用锁而使程序变慢,因为在实现多线程之前我遇到了这个问题,而且争用应该很低,因为CFG构建应该占用一个线程。比更新进度条要多得多的时间。此外,错误的发生频率不是很高,因此写入错误日志的频率不会太高,不足以证明很多争论。

干杯。

修改2: 进度条代码,以防影响内存使用

class ProgressBar:
    def __init__(self, iteration, total, prefix='', suffix='', decimals=1, length=100, fill='█'):
        self.iteration = iteration
        self.total = total
        self.prefix = prefix
        self.suffix = suffix
        self.decimals = decimals
        self.length = length
        self.fill = fill
        self.errors = 0

    def increment_work(self):
        self.iteration += 1

    def increment_errors(self):
        self.errors += 1

    def print_progress_bar(self):
        percent = ("{0:." + str(self.decimals) + "f}").format(100 * (self.iteration / float(self.total)))
        filled_length = int(self.length * self.iteration // self.total)
        bar = self.fill * filled_length + '-' * (self.length - filled_length)
        print('%s |%s| %s%% (%s/%s) %s, %s %s' % (self.prefix, bar, percent, self.iteration, self.total, self.suffix, str(self.errors), 'errors'), end='\r')
        # Print New Line on Complete
        if self.iteration == self.total:
            print()

0 个答案:

没有答案