1

This is the code I am looking to modify in python2 or 3. The for j loop with the nested for i loop is what needs to be put into multiple processes. This code takes each pixel and determines it color (for my computer graphics class). As an added bonus I thought using subprocesses or multiprocessing would be helpful.

from __future__ import division, print_function

from util import *

def raytrace(scene, img, updateFn=None):
    width,height=img.size
    camera=scene.camera
    camera.setResolution(width, height)
    for j in range(height):
        for i in range(width):
            ray=camera.ijRay(i,j)
            color=raycolor(scene,ray,Interval(),3)
            img.setPixel((i,j),color.quantize(255))
        if updateFn:
            updateFn()

The following code is my attempt to break the image into 4 areas and edit the 'img' by moving the for loops into a separate method and passing it all the necessary variables. Then I labeled each process I wanted to run and used .start() for them and .join() to allow them all to finish. Unfortunately the 'img' originally passed to the raytrace method remains blank.

# tracer1: Simple ray-tracing viewer with camera looking down z axis and
#          viewing plane on the xy plane.

from __future__ import division, print_function

from util import *
from multiprocessing import Process
from image import Image

def raytrace(scene, img, updateFn=None):
    width,height=img.size
    camera=scene.camera
    camera.setResolution(width, height)
    w=width//2
    h=height//2
    a=Process(target=part,args=(scene,img,camera,0,0,w,h,updateFn))
    a.start()
    b=Process(target=part,args=(scene,img,camera,w,0,width,h,updateFn))
    b.start()
    c=Process(target=part,args=(scene,img,camera,0,h,w,height,updateFn))
    c.start()
    d=Process(target=part,args=(scene,img,camera,w,h,width,height,updateFn))
    d.start()
    a.join()
    b.join()
    c.join()
    d.join()

def part(scene,img, camera,swidth,sheight,ewidth,eheight,updateFn):
    for j in range(sheight,eheight+1):
        for i in range(swidth,ewidth+1):
            ray=camera.ijRay(i,j)
            color=raycolor(scene,ray,Interval(),3)
            img.setPixel((i,j),color.quantize(255))
        if updateFn:
            updateFn()

Any thoughts?

jfs
  • 399,953
  • 195
  • 994
  • 1,670
user3618914
  • 43
  • 1
  • 6
  • To avoid copying the image to/from child processes, you could put it in a shared memory e.g., see [Use numpy array in shared memory for multiprocessing](http://stackoverflow.com/q/7894791/4279) – jfs May 09 '14 at 12:32

1 Answers1

0

multiprocessing is probably not the right tool here. The img remains blank because multiprocessing is a hack that spawns new processes and requires explicit communication. One quarter of the image is filled in each of the four subprocesses, but you didn't write logic to put the pieces back together, so in the end you see the original, still-blank imgfrom the parent process. I'd recommend running the program four times explicitly, creating four files, and then joining them into a single big image --- using another runner script to do that, with the subprocess module.

Note also that PyPy makes ray-tracing kinds of programs incredibly faster (much more than 4x).

Armin Rigo
  • 12,048
  • 37
  • 48
  • *"multiprocessing is a hack that spawns new processes"* -- I hear you. A separate memory space by default is a feature for a new process, not a bug -- it avoids many synchronisation issues. `multiprocessing` starts new processes as *advertised*. The issue is that multiple threads (unrelated to `multiprocessing`) that *are* sharing the same space may be limited by GIL for CPU-bound tasks if the objects do not release GIL during computations (numpy, lxml, regex, ctypes calls may release GIL). It may force `multiprocessing` usage in non-ideal cases for it. – jfs May 09 '14 at 12:34