Поскольку fork() дублирует пространство памяти родительского процесса. Когда родительский процесс велик, я подозреваю, что это может привести к сбоям при выделении памяти, даже если дочернему процессу не нужна вся эта память.
Чтобы решить эту проблему, я исследовал, как выполнять внешние команды. без дублирования всей памяти родительского процесса, сохраняя при этом вывод команды. Я придумал два альтернативных метода, которые используют одну и ту же сигнатуру функции run_command и используют одну и ту же функцию main для последовательного сравнения.
Метод 1: Использование многопроцессорной обработки с «spawn»
Код: Выделить всё
import multiprocessing
def _internal_run_command(cmd):
import subprocess
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)
output, _ = process.communicate()
return output
def run_command(cmd):
multiprocessing.set_start_method("spawn", force=True)
with multiprocessing.Pool(1) as pool:
result = pool.apply(_internal_run_command, (cmd,))
return result
Код: Выделить всё
import os
def run_command(cmd):
r, w = os.pipe()
try:
pid = os.posix_spawnp(
cmd[0], # File to execute
cmd, # argv
os.environ.copy(), # env
file_actions=[
(os.POSIX_SPAWN_DUP2, w, 1), # Redirect stdout to write end of pipe
(os.POSIX_SPAWN_CLOSE, r), # Close read end in child
],
)
os.close(w) # Close write end in parent
output = b""
while True:
chunk = os.read(r, 1024)
if not chunk:
break
output += chunk
os.close(r)
os.waitpid(pid, 0)
return output.decode()
except Exception as e:
print(e)
Код: Выделить всё
if __name__ == "__main__":
output = run_command(["ls", "-l"])
print(output)
Аспект
Метод 1: многопроцессорная обработка с "порождением"
Метод 2: Использование os.posix_spawnp()
Кроссплатформенная совместимость
Да (работает в Linux, macOS, Windows)
Нет (только POSIX: Linux, macOS)
Сложность реализации
Использует модули высокого уровня (
Код: Выделить всё
multiprocessingТребуется ручное управление каналами и файловыми дескрипторами
Производительность
Затраты на запуск нового интерпретатора Python
Эффективное прямое выполнение без дополнительных затрат
< /tr>
Мои опасения:
Это довольно низкоуровневый инфраструктурный код, который реализуется вручную. и может привести к неожиданным проблемам. Меня беспокоит то, что, вручную обрабатывая процессы, каналы и файловые дескрипторы, мы заново изобретаем велосипед для решения проблемы, с которой, по-видимому, мы сталкиваемся не первыми.
Мои вопросы:
- Есть ли лучший способ выполнения внешних команд из устройства с интенсивным использованием памяти Процесс Python в Linux, который позволяет избежать fork() и позволяет мне захватывать вывод?
- Например, есть ли способ использовать подпроцесс или другой модуль стандартной библиотеки, который не использует fork ()?
- Есть ли еще плюсы и минусы, которые мне следует учитывать между эти два метода?
- Если нет лучших альтернатив, я бы хотелось бы узнать больше о возможных компромиссах.
- В настоящее время мы работаем в системах Linux, поэтому приемлемы решения только для POSIX.
< li>Основная цель — избежать сбоев при выделении памяти из-за того, что fork() дублирует большое пространство памяти родительского элемента. процесс. - Захват вывода внешней команды важен для функциональности нашего приложения.
Я пытался выяснить, противоречит ли это правилам, читая мета-вопросы, но не был уверен, поэтому добавляю этот раздел явно.
- Я использовал ChatGPT для создания альтернатив (но проверял их перед публикацией и это обе альтернативы).
- Я использовал ChatGPT, чтобы формализовать вопрос, но все детали стали точными после многих итераций результатов.
Подробнее здесь: https://stackoverflow.com/questions/793 ... rge-python
Мобильная версия