2011-08-16 9 views
5

Ho un server contorto che esegue un task "lungo" per ogni richiesta, quindi rimando al thread di ogni chiamata. In ogni richiesta accedo a una risorsa comune, che viene modificata durante il processo. Ogni richiesta dovrebbe iniziare con i dati originali, quindi uso deepcopy sulla risorsa comune (mentre si richiama un lock acquisito). Funziona, ma penso che non sia abbastanza veloce. Ho la sensazione che la deepcopy stia rallentando un po 'le cose.Filettatura ritorta come evitare la deepcopy

Quali suggerimenti si hanno quando si tratta di un server con thread twistato con mutazione delle risorse?

+0

In che cosa è, non è abbastanza veloce? Il tuo server non è in grado di gestire N richieste al secondo? Una singola richiesta a volte richiede troppo tempo? Diventa più lento man mano che aumenti il ​​numero di richieste simultanee? – stderr

+0

Una singola richiesta non sta richiedendo troppo tempo. Non rallenta quanto aumento il numero di richieste simultanee. La dimensione del pool di thread twisted reactor è impostata su 25. – Catalin

risposta

2

Se ti piace, puoi semplicemente sincronizzare l'accesso alla risorsa condivisa con threading.Lock proprio come faresti in qualsiasi altro programma a thread invece di copiarlo.

Indipendentemente da ciò, penso che valga la pena di eseguire il benchmarking del codice con e senza la deepcopy e di misurare altrimenti per capire quanto sia buona o cattiva la performance prima di fare ottimizzazioni. Forse il motivo per cui è lento non ha nulla a che fare con la deepcopy.

MODIFICA relativa all'utilizzo del blocco: Ciò che intendo è che è possibile utilizzare un blocco a grana fine su questa risorsa. Presumo che i tuoi thread stiano facendo di più che accedere a una risorsa condivisa. Puoi provare a trarre vantaggio da più thread che fanno lavoro e quindi sincronizzare l'accesso solo a quella "sezione critica" che implica la scrittura sulla risorsa condivisa. Si potrebbe anche investigare rendendo la risorsa condivisa a rischio di sicurezza. Ad esempio, se hanno un oggetto condiviso, 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() 

Il punto è proprio questo il suddetto scopo potrebbe potenzialmente essere condiviso tra più thread senza deepcopy da un attento uso di blocchi. Non è banale identificare tutti i casi in cui ciò potrebbe essere necessario e le strategie di blocco a grana fine possono essere più difficili da eseguire il debug e introdurre ancora un sovraccarico.

Detto questo, potresti non aver bisogno di thread, lock o deepcopy e senza il benchmark del tuo codice non è chiaro se hai un problema di prestazioni che deve essere risolto. Sono curioso cosa ti fa pensare che il tuo codice debba essere, o deve essere, più veloce?

+0

Un +1 definito per il sentimento "benchmark e profilo first". Troppo spesso le persone ottimizzano le cose sbagliate, anche quando sanno che qualcosa è effettivamente lento. – Glyph

+0

Se sincronizzo l'accesso alla risorsa con threading.Lock significherebbe che vado a thread singolo. Il benchmarking della cosa è decisamente su TODO. – Catalin

+0

Le singole operazioni sulle liste sono thread-safe in CPython, quindi 'SharedList' qui non fa nulla di utile. –

3

Prova a operare con i dati minimi possibili nei tuoi thread di lavoro. Passa tutti i dati di cui hanno bisogno come argomenti e prende tutto il loro output come valore di ritorno (il valore con cui si attiva il comando Deferred) anziché come mutazioni agli input.

Quindi integrare i risultati nella struttura di dati comune nella filettatura del reattore.

Questo consente di ragionare sul lavoro in isolamento ed evitare qualsiasi blocco aggiuntivo (che si traduce in contenimento, rallentando le cose oltre a renderle più confuse).

+0

Ti capita di avere qualche esempio/tutorial da condividere? – Catalin