В последнее время мы столкнулись с проблемой в нашем проекте, когда пытались превратить канал подпроцесса в целое изображение в кодировке base64 (около 355 КБ) в его родительский процесс: но картинки казались случайно обрезанными, и мы до сих пор не получаем такое поведение и не нашли решения .
Мы нашли обходной путь для передачи этих изображений с использованием связи на основе временных файлов, но мы все еще хотим понять проблему, касающуюся этих ограничений межпроцессного взаимодействия.
Вот наиболее близкий минимальный и воспроизводимый пример, который мы нам удалось создать такое поведение, у нас есть скрипт python, который пытается извлечь данные из подпроцесса узла, который генерирует данные для извлечения. Но длина данных, которую может получить родительский процесс, кажется ограниченной недетерминированным c способом.
В этом примере проверяется равенство между запрошенной длиной данных и фактической полученной длиной.
#!/usr/bin/env python3
import base64
import sys
import json
import subprocess
def test(l, executable):
process = subprocess.Popen(
executable,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
stdout, stderr = process.communicate(input=json.dumps(l).encode())
exit_code = process.returncode
if exit_code != 0:
raise RuntimeError("fail : " + str(stderr))
result = base64.b64decode(stdout.decode("utf-8"))
assert len(result) == l, f"{len(result)} != {l}"
print(f"Success: {len(result)} == {l}")
if __name__ == "__main__":
l = int(sys.argv[1]) if len(sys.argv) > 1 else 355000
try:
test(l, ["./test.js"])
except AssertionError as e:
print("fail :", e)
#!/usr/bin/env node
const http = require("http");
const serveHandler = require("serve-handler");
const btoa = require("btoa");
const EXIT_CODE_SUCCESS = 0;
const EXIT_CODE_ERROR = 4;
async function getDataFromStdin() {
return new Promise((resolve, reject) => {
let receivedData = '';
process.stdin.on("data", chunk => {
receivedData += chunk.toString();
});
process.stdin.on("end", () => {
result = resolve(JSON.parse(receivedData));
return result;
});
})
}
async function main(){
const len = await getDataFromStdin();
const base64 = btoa("0".repeat(Number(len)));
process.stdout.write(base64);
}
let errorCode = EXIT_CODE_SUCCESS;
main()
.catch(err => {
console.error(err);
errorCode = EXIT_CODE_ERROR;
}).finally(() => {
process.exit(errorCode);
});
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 1
Success: 1 == 1
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 1000
Success: 1000 == 1000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 30000
Success: 30000 == 30000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 60000
fail : 49152 != 60000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 60000
Success: 60000 == 60000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 120000
fail : 49152 != 120000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 120000
fail : 98304 != 120000
vagrant@sc-dev-machine:/home/vagrant $
Мы также попробовали решение на основе subprocess.check_output()
, но без лучшего результата.
Каким может быть объяснение этому? EOF завершил порции данных между процессами и по каналу? Разве буферизация (которая, как мы подозреваем, является причиной) не способна передавать целые данные?
Существует ли проверенный подход для передачи данных (например, файлов или изображений) в процессе без ограничений по длине?
edit: Вот также некоторые сведения об окружающей среде:
vagrant@sc-dev-machine:/home/vagrant $ uname -a
Linux sc-dev-machine 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
vagrant@sc-dev-machine:/home/vagrant $ python3 --version
Python 3.6.8