15.12.2022 Views

Python Eficaz

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

operação atômica. É o que aconteceu neste caso.

O método increment do objeto Counter parece bem simples.

counter.count += offset

Contudo, o operador += usado em um atributo de objeto instrui o Python para,

na verdade, fazer três coisas separadas por debaixo dos panos. O comando

anterior é equivalente ao seguinte código:

value = getattr(counter, 'count')

result = value + offset

setattr(counter, 'count', result)

As threads do Python que estão incrementando o contador podem ser suspensas

após o término de qualquer uma dessas três operações. Isso é problemático

quando a maneira com que as operações podem ser escalonadas fazem com que

versões antigas de value sejam atribuídas ao contador. O código a seguir mostra

um exemplo de má interação entre duas threads, A e B:

# Rodando na thread A

value_a = getattr(counter, 'count')

# Contexto é transferido para a thread B

value_b = getattr(counter, 'count')

result_b = value_b + 1

setattr(counter, 'count', result_b)

# Contexto é transferido de volta para a thread A

result_a = value_a + 1

setattr(counter, 'count', result_a)

A thread A “atropelou” a thread B, apagando todos os seus passos de incremento

do contador. Foi exatamente isso o que aconteceu com o exemplo do sensor ali

atrás.

Para evitar esse tipo de condição de corrida em seus dados (também conhecidos

como data racing conditions ou simplesmente data races) e outras formas de

corrupção em estruturas de dados, o Python oferece um conjunto bastante

robusto de ferramentas no módulo nativo threading. A mais simples e útil delas é

a classe Lock, que implementa uma trava de exclusão mútua (mutual-exclusion

lock, ou mutex).

www.full-ebook.com

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!