Параллелизм Java: CAS против блокировки [закрыто]


Я читаю книгу параллелизм Java на практике. В главе 15 они говорят о неблокирующих алгоритмах и compare-and-swap (CAS) метод.

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

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

Я знаю, что, возможно, нет строгого правила, когда использовать что. но я просто хотел бы услышать некоторые мнения, опыт работы с новой концепцией КАС.

5 65

5 ответов:

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

основная проблема с CAS заключается в том, что гораздо сложнее правильно программировать, чем блокировать. Имейте в виду, блокировка, в свою очередь, гораздо сложнее использовать правильно, чем передача сообщений или СТМ, так что не принимайте это как сигнал одобрения для использования замков.

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

неблокирующие алгоритмы обычно масштабируются лучше, потому что они имеют более короткие "критические секции", чем алгоритмы на основе блокировки.

вы можете посмотреть на цифры между a ConcurrentLinkedQueue и BlockingQueue. То, что вы увидите это CAS заметно быстрее при умеренной (более реалистичной в реальных приложениях) конкуренции потоков.

самое привлекательное свойство неблокирующий алгоритмы-это тот факт, что если один поток терпит неудачу (Cache miss или хуже, seg fault), то другие потоки не заметят этого сбоя и могут двигаться дальше. Однако при приобретении замка, если замок удерживается поток имеет какой-то сбой ОС, каждый другой поток, ожидающий освобождения блокировки, также будет поражен сбоем.

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

вы должны прочитать о Майкл и Скотт Очереди, это реализация очереди для ConcurrentLinkedQueue и объясняет, как обрабатывать двустороннюю, потокобезопасную, атомарную функцию с одним CAS.

есть хорошая книга, сильно связанная с темой параллелизма без блокировки: "искусство многопроцессорного программирования" Мориса Херлихи

Если вы ищете сравнение реального мира, вот один. Наше приложение имеет два (2) потока 1) поток чтения для захвата сетевых пакетов и 2) поток потребителя, который принимает пакет, подсчитывает его и сообщает статистику.

поток #1 обменивается одним пакетом за раз с потоком #2

результат № 1 - использует пользовательский обмен на основе CAS, используя те же принципы, что и SynchronousQueue, где наш класс называется CASSynchronousQueue:

30,766,538 packets in 59.999 seconds ::  500.763Kpps, 1.115Gbps 0 drops
libpcap statistics: recv=61,251,128, drop=0(0.0%), ifdrop=0

результат № 2 - когда мы заменяем нашу реализацию CAS на стандартную java SynchronousQueue:

8,782,647 packets in 59.999 seconds ::  142.950Kpps, 324.957Mbps 0 drops 
libpcap statistics: recv=69,955,666, drop=52,369,516(74.9%), ifdrop=0

Я не думаю, что разница в производительности не может быть более понятнее.