pipe large amount of data to stdin while using subprocess.Popen

后端 未结 10 614
花落未央
花落未央 2020-12-08 11:08

I\'m kind of struggling to understand what is the python way of solving this simple problem.

My problem is quite simple. If you use the follwing code it will hang. T

10条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-08 11:58

    Using the aiofiles & asyncio in python 3.5:

    A bit complicated, but you need only 1024 Bytes memory to writing in stdin!

    import asyncio
    import aiofiles
    import sys
    from os.path import dirname, join, abspath
    import subprocess as sb
    
    
    THIS_DIR = abspath(dirname(__file__))
    SAMPLE_FILE = join(THIS_DIR, '../src/hazelnut/tests/stuff/sample.mp4')
    DEST_PATH = '/home/vahid/Desktop/sample.mp4'
    
    
    async def async_file_reader(f, buffer):
        async for l in f:
            if l:
                buffer.append(l)
            else:
                break
        print('reader done')
    
    
    async def async_file_writer(source_file, target_file):
        length = 0
        while True:
            input_chunk = await source_file.read(1024)
            if input_chunk:
                length += len(input_chunk)
                target_file.write(input_chunk)
                await target_file.drain()
            else:
                target_file.write_eof()
                break
    
        print('writer done: %s' % length)
    
    
    async def main():
        dir_name = dirname(DEST_PATH)
        remote_cmd = 'ssh localhost mkdir -p %s && cat - > %s' % (dir_name, DEST_PATH)
    
        stdout, stderr = [], []
        async with aiofiles.open(SAMPLE_FILE, mode='rb') as f:
            cmd = await asyncio.create_subprocess_shell(
                remote_cmd,
                stdin=sb.PIPE,
                stdout=sb.PIPE,
                stderr=sb.PIPE,
            )
    
            await asyncio.gather(*(
                async_file_reader(cmd.stdout, stdout),
                async_file_reader(cmd.stderr, stderr),
                async_file_writer(f, cmd.stdin)
            ))
    
            print('EXIT STATUS: %s' % await cmd.wait())
    
        stdout, stderr = '\n'.join(stdout), '\n'.join(stderr)
    
        if stdout:
            print(stdout)
    
        if stderr:
            print(stderr, file=sys.stderr)
    
    
    if __name__ == '__main__':
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
    

    Result:

    writer done: 383631
    reader done
    reader done
    EXIT STATUS: 0
    

提交回复
热议问题