1

I have the following program which is a Boggle solver:

import logging
import multiprocessing
from random import choice
from string import ascii_uppercase


def get_grid(size=None, letters=None):
    if size:
        grid = {(x, y): choice(ascii_uppercase) for x in range(size[0]) for y in
                range(size[1])}
    elif letters:
        grid = {}
        rows = letters.split()
        for y, row in enumerate(rows):
            for x, letter in enumerate(row):
                grid[x, y] = letter

    return grid


def print_grid(grid):
    s = ''
    for y in range(size[1]):
        for x in range(size[0]):
            s += grid[x, y] + ' '
        s += '\n'

    print s


def get_neighbours():
    neighbours = {}
    for position in grid:
        x, y = position
        positions = [(x - 1, y - 1), (x, y - 1), (x + 1, y - 1), (x + 1, y),
                     (x + 1, y + 1), (x, y + 1), (x - 1, y + 1), (x - 1, y)]
        neighbours[position] = [p for p in positions if
                                0 <= p[0] < size[0] and 0 <= p[1] < size[1]]
    return neighbours


def get_wordlist():
    stems = set()
    wordlist = set()

    with open('words.txt') as f:
        for word in f:
            word = word.strip().upper()
            wordlist.add(word)

            for i in range(len(word)):
                stems.add(word[:i + 1])
    return wordlist, stems


def path_to_word(path):
    return ''.join([grid[p] for p in path])


def search(path):
    word = path_to_word(path)

    if word not in stems:
        return

    if word in wordlist:
        paths.append(path)

    for next_pos in neighbours[path[-1]]:
        if next_pos not in path:
            search(path + [next_pos])


def get_words():
    for position in grid:
        logging.info('searching %s' % str(position))
        search([position])
    return {path_to_word(p) for p in paths}

if __name__ == '__main__':

    logging.basicConfig(level=logging.WARNING)
    size = 4, 4
    grid = get_grid(size=size)
    print_grid(grid)
    neighbours = get_neighbours()
    wordlist, stems = get_wordlist()
    paths = []

    #words = get_words()

    pool = multiprocessing.Pool(processes=4)
    results = pool.map(search, grid)
    words = [path_to_word(p) for p in paths]

    print sorted(words, key=len, reverse=True)

When I run it I get the following message:

   Traceback (most recent call last):
     File "C:/Users/will/PycharmProjects/boggle/boggle.py", line 103, in <module>
       results = pool.map(search, grid)
     File "C:\Python27\lib\multiprocessing\pool.py", line 251, in map
       return self.map_async(func, iterable, chunksize).get()
     File "C:\Python27\lib\multiprocessing\pool.py", line 567, in get
       raise self._value
   NameError: global name 'grid' is not defined

The program works fine when I don't try to use multiprocessing module, i.e. comment out the 3 lines:

pool = multiprocessing.Pool(processes=4)
results = pool.map(search, grid)
words = [path_to_word(p) for p in paths]

and uncomment:

words = get_words()

I'm guessing that multiprocessing changes variable scoping somehow?

Guy Coder
  • 24,501
  • 8
  • 71
  • 136
eggbert
  • 3,105
  • 5
  • 30
  • 39
  • since you don't provide a words.txt, we can't test the code, but your ```path_to_word``` references ```grid``` and it is not defined locally – bj0 Sep 24 '15 at 17:08
  • Words.text is just an English dictionary. Grid is defined globally and it works when not using multiprocessing. – eggbert Sep 24 '15 at 18:04
  • Oh I see. In general you don't want to use global variables when using multiprocessing, as they each get separate copies of them when the processes are created. Any changes to them inside the worker processes (modifying path, for instance) will not be visible in the main process. – bj0 Sep 24 '15 at 23:43

0 Answers0