2013-11-08 3 views
2

Я использую бутылку с сервером cherrypy для использования многопоточности. Насколько я понимаю, каждый запрос обрабатывается другим потоком. Поэтому дается следующий код:Я не могу понять многопоточность с использованием черри/бутылки

from bottle import request, route 

somedict = {} 

@route("/read") 
def read(): 
    return somedict 


@route("/write", method="POST") 
def write(): 
    somedict[request.forms.get("key")] = request.forms.get("value") 

Возможно ли быть потокобезопасным? Что делать, если поток демона был запущен для управления somedict, скажем, что это словарь активных сеансов, а сеансы истекли ничейных нитей демона? Если бы не было достаточно простого мехинизма блокировки, и мне нужно было бы использовать его при чтении, записи и в потоке демона или просто в потоке демона?

Также, как я понимаю, черри - это настоящий многопоточный сервер. Есть ли более правильный метод, который я должен использовать для внедрения потока демона при использовании cherrypy, поскольку потоки pythons - это не настоящие потоки? Я не хочу сильно вникать в среду вишни, предпочитая придерживаться бутылки для этого проекта, поэтому, если это связано с отходом от бутылки/переносом моего приложения на вишневый, тогда на данный момент это не имеет никакого значения. Я все еще хотел бы знать, хотя, как я не видел много в их документации по темам вообще.

ответ

0

Я изначально ответил, что dict является потоковым, но при дальнейшем исследовании этот ответ был неправильным. См. here за хорошее объяснение.

Для быстрого объяснения, представьте два потока выполнения этого кода сразу:

d['k'] += 1 

Они могли бы и прочитать d['k'] в то же время, и, таким образом, вместо того, чтобы быть увеличен на 2, будет только увеличиваться на 1.

Я не думаю, что это проблема блокировки вашего приложения, а всего лишь некоторые данные теряются. Если это неприемлемо, использование threading.Lock довольно просто и не добавляет слишком много накладных расходов.

Here's некоторая хорошая информация о безопасности потоков с помощью CherryPy. Вы также можете использовать вместо CherryPy что-то вроде gunicorn. У этого есть модель рабочего процесса, поэтому каждый somedict будет отличаться для каждого процесса, поэтому не было бы беспокойства по обеспечению безопасности потоков.

+0

Так с помощью bultin нитей и CherryPy somedict может использоваться для безопасного обмена данными между запросами и даже демонами потоками? Это отвечает на мой вопрос, если это так, и делает это намного проще, но для меня это кажется волшебным.Как cherrypy может делиться dict в потоковом безопасном режиме в потоках, которые я порождаю в приложении, в то время как базовый python требует блокировки для такого поведения? Или, возможно, как ваше первое предложение подразумевает, что мое понимание поведения базового python просто неверно? – kryptobs2000

+0

@ kryptobs2000 см. Мой обновленный ответ – korylprince

0

CherryPy основан на потоках Python, поэтому вам следует избегать использования его только в качестве HTTP-сервера (и любого другого собственного HTTP-сервера). Я предлагаю вам перейти на uWSGI, который является многопроцессорным и, следовательно, не имеет проблем с GIL. Поскольку это многопроцессор, вы не сможете использовать простые переменные, разделенные нитями. Вы можете использовать UWSGI SharedArea или любое стороннее хранилище данных.

1

В вашем конкретном примере да, присваивание (однократное) dict, которое вы выполняете, является потокобезопасным.

somedict[request.forms.get("key")] = request.forms.get("value") 

Но, в более общем случае, правильный ответ на ваш вопрос: вы будет действительно необходимо использовать механизм блокировки. Это верно, если, например, вы делаете несколько обновлений для somedict при обработке одного запроса, и вам нужно, чтобы они были сделаны атомарно.

Хорошая новость заключается в том: это, вероятно, так же просто, как мьютекс:

from bottle import request, route 
import threading 

somedict = {} 
somedict_lock = threading.Lock() 

@route("/read") 
def read(): 
    with somedict_lock: 
     return somedict 

@route("/write", method="POST") 
def write(): 
    with somedict_lock: 
     somedict[request.forms.get("key1")] = request.forms.get("value1") 
     somedict[request.forms.get("key2")] = request.forms.get("value2")