Илья Ермаков писал(а):
Примите допущение, что у вас в адресном пространстве не более 1 аппаратного треда (при многих сопрограммах) - и вам не надо думать о повторной входимости и мониторах/критических секциях для каждого объекта.
http://wiki.tcl.tk/1255 - есть вот такая статья, которая показывает подобные проблемы в tcl/tk. Там есть очередь сообщений (на самом деле их две, но это не суть важно), а каждый обработчик события обычно обрабатывается до завершения. Пока он обрабатывается, другое событие не может начаться. Т.е. та самая модель естественной критической секции. Но есть и update (аналог yield). Если мы его вызвали, то другие события могут обработаться посреди нашей "естественной критической секции", т.е. секция сломалась. Для асинхронщины это значит, что мы должны про любую процедуру знать, вызывает ли она yield. И, если вызывает, то у нас произошёл разрыв критической секции на как минимум две - до вызова этой процедуры и после. В случае tcl/tk неудачно сложилось так, что это узнать иногда сложно, иногда нельзя.
Я пришёл к выводу, что обойтись без явного управления параллельностью невозможно. В пьесе должен быть думающий сценарист, который определяет, кто и в каком порядке выходит на сцену. Без него скоординированная работа труппы не получится. Это свойство не какой-то модели параллельности, а параллельности как таковой.
В т.ч. такое действие, как "остановиться, дождаться чего-то и продолжить" тоже неустранимо, а это и есть один из явных примитивов синхронизации. Думаю, можно это сформулировать в виде какой-то теоремы, но пока у меня это на уровне ощущений.
Однопоточность и корутины - это лишь одна из моделей реализации параллельности. "Остановиться, дождаться и продолжить" в ней реализуется в виде, например, цепочки переустанавливающихся таймеров, где по таймеру смотрим, не наступило ли событие, и, если не наступило, ставим следующий таймер (ещё подождём); либо установкой обработчика события, происходящего асинхронно (например, готовность данных из сокета). Соответственно и дедлоки тоже не исключены, просто они будут выглядеть, как никогда не заканчивающиеся цепочки таймеров или никогда не вызывающиеся обработчики событий.
В этом смысле порицать голанг нет смысла. ЧТо нужно делать - это иметь подход, позволяющий рассуждать о дедлоках, а также, на практике, в большинстве достаточно сложных параллельных систем есть динамический монитор дедлоков, к-рый периодически проходит граф ожиданий и ищет в нём циклы.
Код действительно зависит от числа тредов. Если мы хотим оптимизации, то мы можем разрешить устанавливать число тредов как флаг компиляции и запретить менять его для уже готовой программы. Тогда особых потерь нет - кому нравятся корутины и один тред - просто поставь флаг. Как сделано в голанге - я не знаю. Если у них нет защиты от включения второго треда произвольным кодом - тогда да, проблема у них есть. Но она наверняка решается очень маленьким (на несколько строк) патчем к рантайму, после которого ручка просто перестаёт работать