Критическая секция — это блок кода, который не может выполняться более чем одним процессом/потоком одновременно, поэтому критические секции дороги и могут привести к «бутылочному горлышку» производительности на определенном потоке.
Критические секции должны быть максимально короткими, простыми (если возможно) и эффективными.
Например, рассмотрим следующий блок кода, который генерирует новый UUID для общего объекта:
with self._mutex:
# start of lock
try:
self._action.id = str(uuid.uuid4())
self._logger.trace("action generated, action_id={action_id}".format(action_id=self._action.id))
except BaseException as err:
self._logger.error(err,"failed to generate uuid")
# end of lock
Здесь я допустил три распространенные ошибки:
- try & catch, хорошо, я признаю это, возможно, не самая распространенная ошибка, поскольку никто не будет помещать try & catch, который может находиться за пределами критической секции, внутрь нее без веской причины.
- ведение журнала внутри критической секции. Обычно логирование — это дорогая операция ввода-вывода, которую можно было бы выполнить вне критической секции.
- генерация UUID внутри критической секции
Вот другой блок кода, который делает то же самое, только без этих трех ошибок:
try:
action_id = str(uuid.uuid4())
with self._mutex:
# start of lock
self._action.id = action_id
# end of lock
self._logger.trace("action generated, action_id={action_id}".format(id=action_id))
except BaseException as err:
self._logger.error(err,"failed to generate uuid")
Когда вы используете блокировку, помните, что ее цель — избежать одновременного доступа нескольких потоков к общим ресурсам