Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/229.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何处理异步作业的子批次?_Python_Subprocess - Fatal编程技术网

Python 如何处理异步作业的子批次?

Python 如何处理异步作业的子批次?,python,subprocess,Python,Subprocess,我有一组异步作业(大约100个),我想对每个作业使用subprocess.popen分五批运行。我的计划是: 执行作业列表中的前五个作业 大约每分钟轮询一次活动作业(每个作业运行几分钟) 如果一个作业完成,执行下一个作业,始终保证一次运行五个作业 继续,直到我们看完了整个工作列表 在python中有一种已知的模式可以做到这一点吗?在python 2中,我使用了多处理.Pool和子进程的组合来实现这一点。但这确实会以池的进程的形式产生额外的开销 因此,在Python3中,我使用了一个concurr

我有一组异步作业(大约100个),我想对每个作业使用
subprocess.popen
分五批运行。我的计划是:

  • 执行作业列表中的前五个作业
  • 大约每分钟轮询一次活动作业(每个作业运行几分钟)
  • 如果一个作业完成,执行下一个作业,始终保证一次运行五个作业
  • 继续,直到我们看完了整个工作列表

  • 在python中有一种已知的模式可以做到这一点吗?

    在python 2中,我使用了
    多处理.Pool
    子进程的组合来实现这一点。但这确实会以池的进程的形式产生额外的开销

    因此,在Python3中,我使用了一个
    concurrent.futures.ThreadPoolExecutor
    而不是
    multiprocessing.pool

    下面的代码片段显示了如何使用
    ThreadPoolExecutor

    import concurrent.futures as cf
    import logging
    import os
    
    errmsg = 'conversion of track {} failed, return code {}'
    okmsg = 'finished track {}, "{}"'
    num = len(data['tracks'])
    with cf.ThreadPoolExecutor(max_workers=os.cpu_count()) as tp:
        fl = [tp.submit(runflac, t, data) for t in range(num)]
        for fut in cf.as_completed(fl):
            idx, rv = fut.result()
            if rv == 0:
                logging.info(okmsg.format(idx+1, data['tracks'][idx]))
            else:
                logging.error(errmsg.format(idx+1, rv))
    
    runflac
    函数使用
    subprocess
    调用
    flac(1)
    转换音乐文件:

    import subprocess
    
    def runflac(idx, data):
        """Use the flac(1) program to convert a music file to FLAC format.
    
        Arguments:
            idx: track index (starts from 0)
            data: album data dictionary
    
        Returns:
            A tuple containing the track index and return value of flac.
        """
        num = idx + 1
        ifn = 'track{:02d}.cdda.wav'.format(num)
        args = ['flac', '--best', '--totally-silent',
                '-TARTIST=' + data['artist'], '-TALBUM=' + data['title'],
                '-TTITLE=' + data['tracks'][idx],
                '-TDATE={}'.format(data['year']),
                '-TGENRE={}'.format(data['genre']),
                '-TTRACKNUM={:02d}'.format(num), '-o',
                'track{:02d}.flac'.format(num), ifn]
        rv = subprocess.call(args, stdout=subprocess.DEVNULL,
                            stderr=subprocess.DEVNULL)
        return (idx, rv)
    
    更新:

    在Python2.7中,还有另一种技术稍微复杂一些,但避免了使用多处理池的开销

    基本形式是:

    starter = functools.partial(startencoder, crf=args.crf, preset=args.preset)
    procs = []
    maxprocs = cpu_count()
    for ifile in args.files:
        while len(procs) == maxprocs:
            manageprocs(procs)
        procs.append(starter(ifile))
    while len(procs) > 0:
        manageprocs(procs)
    
    (使用
    functools.partial
    是一种为函数设置默认参数的方法。它与原理无关。)
    startencoder
    函数基本上是
    子流程.Popen
    的包装器,但它返回除
    Popen
    实例之外的一些额外信息

    def startencoder(fname, crf, preset):
        """
        Use ffmpeg to convert a video file to H.264/AAC streams in an MP4
        container.
    
        Arguments:
            fname: Name of the file to convert.
            crf: Constant rate factor. See ffmpeg docs.
            preset: Encoding preset. See ffmpeg docs.
    
        Returns:
            A 3-tuple of a Process, input path and output path.
        """
        basename, ext = os.path.splitext(fname)
        known = ['.mp4', '.avi', '.wmv', '.flv', '.mpg', '.mpeg', '.mov', '.ogv',
                '.mkv', '.webm']
        if ext.lower() not in known:
            ls = "File {} has unknown extension, ignoring it.".format(fname)
            logging.warning(ls)
            return (None, fname, None)
        ofn = basename + '.mp4'
        args = ['ffmpeg', '-i', fname, '-c:v', 'libx264', '-crf', str(crf),
                '-preset', preset, '-flags',  '+aic+mv4', '-c:a', 'libfaac',
                '-sn', '-y', ofn]
        try:
            p = subprocess.Popen(args, stdout=subprocess.DEVNULL,
                                stderr=subprocess.DEVNULL)
            logging.info("Conversion of {} to {} started.".format(fname, ofn))
        except:
            logging.error("Starting conversion of {} failed.".format(fname))
        return (p, fname, ofn)
    
    重要的是
    manageprocs
    功能:

    def manageprocs(proclist):
        """
        Check a list of subprocesses tuples for processes that have ended and
        remove them from the list.
    
        Arguments:
            proclist: a list of (process, input filename, output filename)
                    tuples.
        """
        nr = '# of conversions running: {}\r'.format(len(proclist))
        logging.info(nr)
        sys.stdout.flush()
        for p in proclist:
            pr, ifn, ofn = p
            if pr is None:
                proclist.remove(p)
            elif pr.poll() is not None:
                logging.info('Conversion of {} to {} finished.'.format(ifn, ofn))
                proclist.remove(p)
        sleep(0.5)
    

    我正在使用Python2.7,所以我将使用池。谢谢@John我仔细研究了我的2.7代码,找到了一个解决方案,可以避免使用
    池的开销。我添加了这个作为更新。太棒了!非常感谢。