Program to convert mp3 using multiprocessing module is looping

2
import subprocess

from multiprocessing import Process, Lock

def ConverteMusica(a,lock):

    input_file_fmt = '{}.mp3'
    output_file_fmt = a

    for x in range(1, 5):
        subprocess.call(['ffmpeg',
                         '-i',
                         input_file_fmt.format(x),
                         '-acodec',
                         'libmp3lame',
                         '-ac',
                         '2',
                         '-ab',
                         '16k',
                         '-ar',
                         '44100',
                         output_file_fmt.format(x)])


lock = Lock()

MeuConversor1 = Process(target=ConverteMusica,args=("Personalidades_Famosas_Elogiam_Cultura_Vedica.mp3",lock))


MeuConversor1.start()
MeuConversor1.join()

I tried to adapt the program that I had already switching threading by multiprocessing. I do not know why the program is looping! What's wrong?

    
asked by anonymous 10.04.2018 / 14:43

1 answer

6

For the time being I'm going to get you the error in your code, because I need to analyze with more time, but an alternative to the problem is to use the asyncio module, since the actual processing of your program runs outside of Python, then you will not have problems with GIL . Basically you will only be using Python to start the processes.

With asyncio , you could do something similar to:

import asyncio

async def command(*args):
  process = await asyncio.create_subprocess_exec(*args, stdout=asyncio.subprocess.PIPE)
  stdout, stderr = await process.communicate()
  return stdout.decode() if process.returncode == 0 else stderr.decode()

Since I can not reproduce the same command you want with ffmpeg , I'll demonstrate a code that does ping on multiple servers. So:

URLS = [
  'woss.eng.br',
  'pt.stackoverflow.com',
  'chat.stackexchange.com',
  '127.0.0.1'
]

commands = [command('ping', '-c', '10', url) for url in URLS]

The list commands will be composed of all the commands that I want to execute in parallel, that is, in this case, the ping command on the four servers indicated. So, just set the asyncio event loop and wait for responses:

loop = asyncio.get_event_loop()
processes = asyncio.gather(*commands)
result = loop.run_until_complete(processes)
loop.close()

print(result)

The complete code, with some print more to follow the execution, would be:

import asyncio, time

async def command(*args):
  process = await asyncio.create_subprocess_exec(*args, stdout=asyncio.subprocess.PIPE)
  print('Iniciado o processo', process.pid)
  stdout, stderr = await process.communicate()
  return stdout.decode() if process.returncode == 0 else stderr.decode()

URLS = [
  'woss.eng.br',
  'pt.stackoverflow.com',
  'chat.stackexchange.com',
  '127.0.0.1'
]

START = time.time()

commands = [command('ping', '-c', '10', url) for url in URLS]

loop = asyncio.get_event_loop()
processes = asyncio.gather(*commands)
result = loop.run_until_complete(processes)
loop.close()

END = time.time()

print(result)
print('Tempo', END - START)

See working at Repl.it

Running, you will see that it will run in approximately 9 seconds, which is the approximate time of the ping command for a domain, transferring 10 packets, even if four commands were executed, different if the same commands run in sequence , totaling almost 40 seconds.

    
11.04.2018 / 03:02