Реализация одной и той же функции для другого результата в Python

89
8

Мне нужна моя программа для выполнения определенной функции параллельно. Но эта функция разветвляется на разные результаты в зависимости от того, как пользователь взаимодействует с программой. У меня есть простой графический интерфейс в модуле с именем threadGUI.py, который имеет два варианта: загрузка и загрузка. Эти параметры создают словари, содержащие переменные, связанные с функцией. Эти словари хранятся в основном словаре, который хранится в модуле thread_test.py. Они отлично работают при выполнении одного за другим, но когда я пытаюсь сделать это параллельно, что-то идет не так. Связанный с потоком код в threadGUI.py:

def OnStartClick(self):
for i in thread_test.dictList.values(): #the main dictionary is stored as a global in thread_test.py
thread = Thread(target = thread_test.begin_tests, args = (i, ))
thread.start()
print "thread finished...exiting"

Вышеупомянутая функция вызывает функцию begin_test в модуле thread_test.py. Функция выглядит так:

def begin_tests(arg): 
print arg
print dictList
dictItem = arg
print dictItem
if dictItem['Type'] == "HTTP_Downloading":
print "DOWNLOAD"
elif dictItem['Type'] == "FTP_Uploading":
print "UPLOAD"
else:
print "Invalid input"
sys.exit(1)

Это упрощенный пример моего кода. Моя проблема в том, что мой код выполняет только одну функцию из двух вместо них. Поэтому, если бы я создал словарь, который назывался загрузкой, загрузкой, загрузкой, тогда он выполнил бы три загрузки вместо желаемого шаблона.

спросил(а) 2012-06-05T16:07:00+04:00 8 лет, 3 месяца назад
1
Решение
69

Проблема не в размещенном коде:

from threading import Thread

dictList = {
'foo': { 'Type': 'HTTP_Downloading' },
'bar': { 'Type': 'FTP_Uploading' },
'baz': { 'Type': 'HTTP_Downloading' }
}

def begin_tests(arg):
print arg
print dictList
dictItem = arg
print dictItem
if dictItem['Type'] == "HTTP_Downloading":
print "DOWNLOAD"
elif dictItem['Type'] == "FTP_Uploading":
print "UPLOAD"
else:
print "Invalid input"
sys.exit(1)

def OnStartClick(self):
for i in dictList.values(): #the main dictionary is stored as a global in thread_test.py
thread = Thread(target = begin_tests, args = (i, ))
thread.start()
print "thread finished...exiting"

OnStartClick(None)

Результаты в:

{'Type': 'HTTP_Downloading'}
{'baz': {'Type': 'HTTP_Downloading'}, 'foo': {'Type': 'HTTP_Downloading'}, 'bar': {'Type': 'FTP_Uploading'}}
{'Type': 'HTTP_Downloading'}
{DOWNLOAD
{'Type': 'FTP_Uploading'}
'Type': 'HTTP_Downloading'}
{'baz': {'Type': 'HTTP_Downloading'}, 'foo': {'Type': 'HTTP_Downloading'}, 'bar': {'Type': 'FTP_Uploading'}}
{'baz': {'Type': 'HTTP_Downloading'}, 'foo': {'Type': 'HTTP_Downloading'}, 'bar': {'Type': 'FTP_Uploading'}}
thread finished...exiting
{'Type': 'HTTP_Downloading'}
DOWNLOAD
{'Type': 'FTP_Uploading'}
UPLOAD

По предположению, вы повторно используете внутренний dict.

ОБНОВИТЬ:

Я думаю, что этот случай лучше решается с помощью стратегии рабочего-пула и очереди. Что-то вроде:

from Queue import Queue
from threading import Thread

queue = Queue() # Replaces the dictList

threads = []
for n in range(10):
thread = Thread(target = worker, args = (begin_tests, queue, ))
thread.start()
threads.append(thread)

Stop = object()
def worker(work, queue):
while True:
task = queue.get()
if task is Stop:
break
work(task)

Используйте его так:

queue.put({ 'Type': 'HTTP_Downloading' })
queue.put({ 'Type': 'FTP_Uploading' })
queue.put({ 'Type': 'HTTP_Downloading' })
queue.put(Stop)

Это само по себе не затрагивает проблему мутации диктонов; это должно быть исправлено в другом месте. Эта стратегия имеет два преимущества: она сохраняет порядок задач и не рискует потерять задачи: dict предоставляет ограниченные гарантии параллелизма, тогда как Queue() гарантированно будет потокобезопасным.

ответил(а) 2012-06-05T16:35:00+04:00 8 лет, 3 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема