pythonmultiprocessing

Program running indefinitely in multiprocessing


import multiprocessing
from PIL import Image

name = input("Enter the file name: ")

def decode_file(filename):
    with open(filename, mode='rb') as file:
        binary_data = file.read()

    binary_list = []
    for byte in binary_data:
        binary_list.append(format(byte, '08b'))
    return binary_list

binary_list = decode_file(name)

l = len(binary_list)
no_of_bytes = l // 8

def make_row_list():
    row_list = []
    for i in range(0, l, 135):
        row_list.append(binary_list[i:i + 135])
    return row_list

row_list = make_row_list()

def fill_row(shared_pixels, width, row_data, count):
    x_coordinate = 0
    for byte in row_data:
        for bit in byte:
            index = x_coordinate + count * width
            shared_pixels[index] = int(bit)
            x_coordinate += 1

def fill_img(width, height):
    shared_pixels = multiprocessing.Array('i', width * height)
    processes = []
    count = 0
    for row_data in row_list:
        p = multiprocessing.Process(target=fill_row, args=(shared_pixels, width, row_data, count))
        p.start()
        processes.append(p)
        count += 1
    for process in processes:
        process.join()
    return shared_pixels

def create_img():
    width, height = 1080, 1920
    image = Image.new('1', (width, height))

    if no_of_bytes <= 135:
        x_coordinate = 0
        for byte in binary_list:
            for bit in byte:
                image.putpixel((x_coordinate, 0), int(bit))
                x_coordinate += 1
    elif no_of_bytes <= 259200:
        shared_pixels = fill_img(width, height)
        for y in range(height):
            for x in range(width):
                image.putpixel((x, y), shared_pixels[x + y * width])

    image.save('hi.png')
    image.show()

create_img()

When i run this program it asks for file name then keeps asking for file name indefinitely. The program was running fine before i added multiprocessing. So i think multiprocessing is to be blamed for this. I am new with multiprocessing so any help will be much appreciated :D


Solution

  • This happens because in Python when you create new processes using the multiprocessing module, each new process starts by importing the main module, which includes executing the input statement again.

    To fix this, protect the code that should run once (like the input statement and other statements) with an if __name__ == "__main__": block. This way, the code won't run when imported by a new process:

    Here is a working version:

    import multiprocessing
    from PIL import Image
    
    
    def decode_file(filename):
        with open(filename, mode='rb') as file:
            binary_data = file.read()
    
        binary_list = []
        for byte in binary_data:
            binary_list.append(format(byte, '08b'))
        return binary_list
    
    
    def make_row_list(binary_list):  # added binary_list
        row_list = []
        l = len(binary_list)
        for i in range(0, l, 135):
            row_list.append(binary_list[i:i + 135])
        return row_list
    
    
    def fill_row(shared_pixels, width, row_data, count):
        x_coordinate = 0
        for byte in row_data:
            for bit in byte:
                index = x_coordinate + count * width
                shared_pixels[index] = int(bit)
                x_coordinate += 1
    
    
    def fill_img(width, height, row_list):  # added row_list
        shared_pixels = multiprocessing.Array('i', width * height)
        processes = []
        count = 0
        for row_data in row_list:
            p = multiprocessing.Process(target=fill_row, args=(shared_pixels, width, row_data, count))
            p.start()
            processes.append(p)
            count += 1
        for process in processes:
            process.join()
        return shared_pixels
    
    
    def create_img(binary_list, no_of_bytes):  # added binary_list and no_of_bytes
        width, height = 1080, 1920
        image = Image.new('1', (width, height))
    
        if no_of_bytes <= 135:
            x_coordinate = 0
            for byte in binary_list:
                for bit in byte:
                    image.putpixel((x_coordinate, 0), int(bit))
                    x_coordinate += 1
        elif no_of_bytes <= 259200:
            # calling make_row_list here
            row_list = make_row_list(binary_list)
            shared_pixels = fill_img(width, height, row_list)
            for y in range(height):
                for x in range(width):
                    image.putpixel((x, y), shared_pixels[x + y * width])
    
        image.save('hi.png')
        image.show()
    
    
    if __name__ == "__main__":
        name = input("Enter the file name: ")
        binary_list = decode_file(name)
        no_of_bytes = len(binary_list) // 8
        create_img(binary_list, no_of_bytes)