簡體   English   中英

子進程參數列表為long

[英]Subprocess argument list to long

我有一個使用subprocess.check_output調用的第三方可執行文件,遺憾的是我的參數列表太長並且反復調用它比用多個參數調用它要慢得多。

由於多次執行命令調用而變慢:

def call_third_party_slow(third_party_path, files):
    for file in files:
        output = subprocess.check_output([third_party_path, "-z", file])
        if "sought" in decode(output):
            return False
    return True

快速但有很多文件時失敗:

def call_third_party_fast(third_party_path, files):
    command = [third_party_path, "-z"]
    command.extend(files) 
    output = subprocess.check_output(command)
    if "sought" in decode(output):
        return False
    return True

有沒有簡單的方法可以解決命令長度限制或輕松分組文件以避免超過os依賴長度?

您可以像這樣批處理文件列表:

def batch_args(args, arg_max):
    current_arg_length = 0
    current_list = []
    for arg in args:
        if current_arg_length + len(arg) + 1 > arg_max:
            yield current_list
            current_list = [arg]
            current_arg_length = len(arg)
        else:
            current_list.append(arg)
            current_arg_length += len(arg) + 1
    if current_list:
        yield current_list

所以方法體看起來像這樣:

os_limit = 10
for args in batch_args(files, os_limit):
    command = [third_party_path, "-z"]
    command.extend(args) 
    output = subprocess.check_output(command)
    if "sought" in decode(output):
        return False
return True

我不確定的兩件事:

  1. exe的路徑是否計入限制? 如果是 - >將其添加到每個批次的限制。 (或者按照exe字符串的長度減少arg_max)
  2. args之間的空間是否計算? 如果不同時刪除+1兩次出現。

將arg_max調整為可能的值。 可能有一些方法可以找到每個操作系統。 這里有一些關於某些操作系統的最大args大小的信息。 該網站還聲明Windows有32k的限制。

也許使用子進程庫有更好的方法,但我不確定。

此外,我沒有做任何異常處理(列表中的args超過最大大小等)

我通過在Windows上使用臨時文件解決了這個問題。 對於Linux,命令可以按原樣執行。

為不同的平台構建完整命令的方法:

import tempfile

temporary_file = 0
def make_full_command(base_command, files):
    command = list(base_command)

    if platform.system() == "Windows":
        global temporary_file
        temporary_file = tempfile.NamedTemporaryFile()
        posix_files = map((lambda f: f.replace(os.sep, '/')),files)
        temporary_file.write(str.encode(" ".join(posix_files)))
        temporary_file.flush()
        command.append("@" + temporary_file.name)
    else:
        command.extend(files)
    return command

將文件用作全局變量可確保在執行后清除它。

這樣我就不必為不同的操作系統找到最大命令長度

如果您不想重新發明最佳解決方案,請使用已經實現此功能的工具: xargs

def call_third_party_slow(third_party_path, files):
    result = subprocess.run(['xargs', '-r', '-0', third_party_path, '-z'],
        stdin='\0'.join(files) + '\0', stdout=subprocess.PIPE,
        check=True, universal_newlines=True)
    if "sought" in result.stdout:
        return False
    return True

您會注意到我也切換到了subprocess.run() ,它在Python 3.5+中可用

如果您確實要重新實現xargs ,則需要找到內核常量ARG_MAX的值,並構建一個大小永遠不會超過此限制的命令行列表。 然后你可以在每次迭代后檢查輸出是否包含sought ,如果有,則立即退出。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM