Pull to refresh

Comments 16

Семафор не избавляет от дедлока. Можно точно также в разных тредах полностью захватить семафор и при попытке захвата второго получить дедлок. И что намного более важно - блокировка (Lock) позволяет защитить фрагмент кода от параллельного выполнения полностью, а семафор ограничивает количество параллельных выполнений, но не препятствует им.

Решить проблему с Deadlock могут помочь 2 правила:

Так как Deadlock — это взаимная блокировка, т.е. захват в прямом и обратном направлении в разных потоках, отсюда вытекает правило. Если в процессах нужно захватывать Lock, то делаем это всегда в одном порядке (направлении).

И второе правило — освобождаем блокировки в обратном порядке их захвата, подобно стеку. Первым захватили — последним отпустили.

А что значит направление захвата?

Для чего нужен join() и что такое daemon? Или основные и фоновые процессы

У нас есть основной (главный) процесс, который содержит весь код нашей программы, и два дополнительных (фоновых) p1, p2. Их мы создаем, когда мы прописываем параметр daemon=True. Так мы как раз и указываем, что эти два процесса будут второстепенными. Если мы не вызовем метод join у фонового процесса, то наша программа завершит свое выполнение, не дожидаясь выполнения p1 и p2.


То ли я тупой, то ли у автора дислексия, то ли он сам не понимает, что он пишет. Но вот где, в какой строке этого сумбурного текста даётся определение, что же такое демон? Ну дружище, блин, ты же пишешь инженерную статью. Есть документация на сайте python.org. Ваша статья должна давать что-то большее, чем эта документация, иначе какой в ней смысл? Ну то есть, какие-то тонкие и непонятные моменты должны быть разъяснены, правильно? Ну давайте вчитаемся в то, что написано в этом рандомно взятом абзаце.

> процесс, который содержит весь код нашей программы и два дополнительных

То есть делаем вывод, что подпроцессы не содержат весь код программы, правильно? А что же они тогда содержат?

> Их мы создаем, когда мы прописываем параметр daemon=True

Ага, то есть если в вашем же примере

if __name__ == '__main__':     
    p1 = Process(target=print_word, args=('bob',), daemon=True)     
    p2 = Process(target=print_word, args=('alice',), daemon=True)

сделать daemon=False, мы не создадим два дополнительных процесса? А что создадим?

Лучше ничего не писать, чем писать такое


А мне статья понравилась.
Хорошее дополнение к документации, несмотря на огрехи. Которые, кстати, легко исправить.

Так напишите статью лучше, а мы оценим.

Как по мне, статья качественная.

Спасибо за интересную статью, а если помимо параллельного выполнения задач нужно, чтобы они между собой обменивались данными? и при этом графический интерфейс отображал прогресс?

Спасибо!
Чтобы обмениваться, multithreading и асихнронка уже используют общую память.
Для обмена между процессами можно использовать очереди (Queue) или каналы данных (pipe).

Обмен данными между процессами можно организовать ещё через сокеты. Так что смотрите на семантику того, чего отображаете. Если это какая-то отдельная программа или упираетесь в gil, то лучше через процессы. Вариантов много.

Хотя, кажется в 3.11 хотели переместить gil в каждый поток, созданный python. Но это не точно.

Вы упомянули GIL, пообещали позже рассказать про его освобождение через time.sleep(), и забыли про это. А ещё в итогах не упомянули этот вполне себе существенный минус. Фактически, все потоки работают на одном ядре. И если нам надо чем то загрузить процессор, мы не получим выигрыша от потоков. Как и от AIO впрочем.

Отдельные потоки

Плюсы:

+ Работают параллельно.

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

Есть смысл. Так как при использовании асинхронности мы самостоятельно переключаем контекст и поток исполнения. А при многопоточности этим занимается операционная система.

Не совсем понимаю....если существует GIL , который не дает потокам работать одновременно, то в чем смысл тогда блокировок и прочего ? если в один момент времени, будет работать только один поток, а все остальные будут спать

Ну, например для того, чтобы безопасно сделать неатомарные манипуляции с общими ресурсами.

Например, у вас есть некий словарь. И вам нужно брать из него значения, производить на основе этого значения какое-то новое значение и сохранять под тем же ключом.

Вы пишете так:
value = my_dict[key]
new_value = calculate_new_value(value)
my_dict[key] = new_value


Теперь представьте, что где-то между первой и третьей строчкой выполнение переключилось на другой поток, и этот другой поток обновил значение my_dict[key]. Когда выполнение вернётся к первому потоку, он просто перезапишет поверх него какое-то уже неактуальное значение. А если бы перед записью в словарь наш код брал бы лок, такого бы не случилось.

Очередная статья про "потоки, процессы и асинхронность" - зачем их столько? Хоть бы примеры какие-то из жизни привели, но нет все какая-то синтетическая копипаста.

Всю эту историю можно свести к тому, что там где код упирается в await - происходит переключение на следующую функцию с периодическим возвратом, пока она не вернет ответ.

А процессы работают через ProcessPoolExecutor, который инитится при старте приложения и, по необходимости, в него запихиваются нужные функции (и тоже периодически проверяется готовность результата)

какие есть способы сделать 2 окна активными? В одном будет видео из OpenCV, а в другом элементы управления (ползунки кнопки)

Sign up to leave a comment.