Витая нить как избежать глубокого копирования - PullRequest
5 голосов
/ 16 августа 2011

У меня есть витой сервер, который выполняет некоторую «длинную» задачу для каждого запроса, поэтому я откладываю выполнение каждого вызова.В каждом запросе я получаю доступ к общему ресурсу, который изменяется во время процесса.Каждый запрос должен начинаться с исходных данных, поэтому я использую Deepcopy на общем ресурсе (при вызове захвата блокировки).Это работает, но я думаю, что это не достаточно быстро.У меня такое ощущение, что глубокая копия немного тормозит.

Какие у вас есть предложения при работе с многопоточным витым сервером с мутацией ресурсов?

Ответы [ 2 ]

3 голосов
/ 17 августа 2011

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

Затем интегрируйте результаты в общую структуру данных в потоке реактора.

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

2 голосов
/ 16 августа 2011

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

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

РЕДАКТИРОВАТЬ, используя блокировку: я имею в виду, что вы можете использовать более тонкую блокировку вокруг этого ресурса. Я предполагаю, что ваши потоки делают больше, чем доступ к общему ресурсу. Вы можете попытаться извлечь выгоду из нескольких потоков, выполняющих работу, а затем синхронизировать доступ только к одному «критическому разделу», который включает запись в общий ресурс. Вы также можете исследовать, как сделать ваш общий ресурс безопасным. Например, если у вас есть общий объект, SillyExampleFriendsList:

class SillyExampleFriendsList(object):
    """Just manipulates a couple lists"""
    def __init__(self):
       self._lock = threading.RLock()
       self._friends = []
       self._enemies = []

    def unfriend(self, x):
       # we lock here to ensure that we're never in a state where
       # someone might think 'x' is both our friend and our enemy.
       self._lock.acquire()
       self._friends.remove(x)
       self._enemies.append(x)
       self._lock.release()

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

Тем не менее, вам может вообще не понадобиться потоки, блокировки или глубокая копия, и без тестирования вашего кода неясно, есть ли у вас проблемы с производительностью, которые необходимо решить. Мне интересно, что заставляет вас думать, что ваш код должен быть или должен быть быстрее?

...