django/python: ошибка при получении значения из словаря

У меня есть код Python/ Django, размещенный в dotcloud и RedHat OpenShift. Для работы с другим пользователем я использую токен и сохраняю его в словаре. Но когда я получаю значение из dict, иногда выдается ошибка (ошибка значения ключа).

import threading

thread_queue = {}

def download(request):
    dl_val = request.POST["input1"]
    client_token = str(request.POST["pagecookie"])
        # save client token as keys and thread object as value in dictionary
    thread_queue[client_token] = DownloadThread(dl_val,client_token)
    thread_queue[client_token].start()
    return render_to_response("progress.html",
              { "dl_val" : dl_val, "token" :      client_token })

Приведенный ниже код выполняется с интервалом в 1 секунду через javascript xmlhttprequest для сервера. Он проверит переменную внутри другого потока и вернет значение на страницу пользователя.

def downloadProgress(request, token):
        # sometimes i use this for check the content of dict
    #resp = HttpResponse("thread_queue = "+str(thread_queue))
    #return resp
    prog, total = thread_queue[str(token)].getValue() # problematic line !
    if prog == 0:
                # prevent division by zero
        return HttpResponse("0")
    percent = float(prog) / float(total)
    percent = round(percent*100, 2)
    if percent >= 100:
        try:
            f_name = thread_queue[token].getFileName()[1]
        except:
            downloadProgress(request,token)
        resp = HttpResponse('<a href="http://'+request.META['HTTP_HOST']+
                            '/dl/'+token+'/">'+f_name+'</a><br />')
        return resp
    else:
        return HttpResponse(str(percent))

После тестирования в течение нескольких дней иногда возвращаются:

thread_queue = {}

Иногда это удается:

thread_queue = {'wFVdMDF9a2qSQCAXi7za': , 'EVukb7QdNdDgCf2ZtVSw': , 'C7pkqYRvRadTfEce5j2b': , '2xPFhR6wm9bs9BEQNfdd': } 

Я никогда не получаю такой результат, когда я запускаю django локально с помощью manage.py runserver и обращаюсь к нему с помощью Google Chrome, но когда я загружаю его в dotcloud или openshift, это всегда вызывает вышеуказанную проблему. Мой вопрос:

  • Как я могу решить эту проблему?
  • Ограничивает ли dotcloud и openshift их использование процессорами Python?
  • Или проблема в словаре Python?

Благодарю вас.

2 ответа

Решение

dotCloud по умолчанию имеет 4 рабочих процесса для службы python. Когда вы запускаете сервер dev локально, вы запускаете только один процесс. Как сказал @martijn, ваша проблема связана с тем, что ваше мнение не будет разделено между этими процессами.

Чтобы решить эту проблему, вы можете использовать что-то вроде redis или memcached для хранения этой информации. Если вам нужно более долговременное решение для хранения данных, тогда лучше использовать базу данных.

dotCloud не ограничивает использование ЦП, ЦП распределяется между другими на одном и том же хосте и позволяет выполнять пакетную загрузку, но в итоге каждый имеет одинаковое количество ЦП.

Глядя на ваш код, вы должны проверить, чтобы убедиться, что в dict есть значение, прежде чем вы к нему получите доступ, или, по крайней мере, окружить код блоком try before, чтобы обработать случай, когда данных там нет.

str_token = str(token)
if str_token in thread_queue:
   prog, total = thread_queue[str_token].getValue() # problematic line !
else:
   # value isn't there, do something else 

Предположительно dotcloud и openshift запускают несколько процессов вашего кода; диктат не будет распределяться между этими процессами.

Обратите внимание, что это также означает, что дополнительные процессы также не будут иметь доступа к вашему дополнительному шагу.

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

Другие вопросы по тегам