LINUX.ORG.RU

Ленивость и многопоточность

 , , , ,


1

7

Говорят люди в интернете, мол используй функциональное программирование, отсутствие состояния, и никаких data race'ов не будет, и соответственно многопоточность будет достигаться легко.

Но тут я подумал о хаскелле и о его ленивости - а ведь ленивость приносит состояние. Допустим мы одну и ту же функцию вызываем из двух разных потоков. Вроде как в хаскелле ленивость кэшируется, и благодадря этому если вызвать одну и ту же функцию 2 раза, результат 2 раза считаться не будет. Но как с этим в многопоточных приложениях? Вдруг функция уже считается в одном потоке, а я ее вызову из другого потока? Чтобы это работало нормально, уже нужны какие-то механизмы синхронизации. А механизмы синхронизации это уже состояние.

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

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

hlebushek ★★ ()

Я подписался на этот бред, вечером почитаю смешные коменты.

true_admin ★★★★★ ()

Тебе ссылки на статьи или тут на потроллить?

qnikst ★★★★★ ()
Ответ на: комментарий от mix_mix

Не, тут нужно SPJ и SM статьи, по поводу того как все устроено и все эти наши gray/black holes. Заодно про unsafe/unsafeDupablePerformIO и прочих друзей.

qnikst ★★★★★ ()
Ответ на: комментарий от vertexua

Чтобы знать, вычислен thunk или нет, надо хранить состояние. А к состоянию могут быть data race'ы.

hlebushek ★★ ()
Ответ на: комментарий от vertexua

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

qnikst ★★★★★ ()

В Хаскеле, емнип, используется STM.
В Эрланге эта проблема зарыта достаточно глубоко в недра BEAM, чтобы о ней париться разработчику. Для него у каждого процесса существует своё собственное «состояние», изолированное от других.

blexey ★★★★★ ()

Главный ключевой термин для гугления qnikst уже назвал: black holes (есть и другие, но это самое важное). Когда один тред обёртку форсирует, он ставит на неё пометку, чтобы другой тред ждал его (если этому другому треду вдруг помеченное замыкание понадобится). Возможные при этом состояния гонки роли не играют, поскольку они на результат выполнения программы в целом влияния не оказывают.

nezamudich ★★ ()

Вдруг функция уже считается в одном потоке, а я ее вызову из другого потока? Чтобы это работало нормально, уже нужны какие-то механизмы синхронизации.

Для чистой функции?

t184256 ★★★★★ ()

http://ezyang.com/jfp-ghc-rts-draft.pdf, а именно:

4.2 Synchronization

We now turn our attention to how thunks are updated. Updating a thunk with its new value constitutes mutation on shared state, thus, thunks up date is an important obstacle on the way to thread-safety.

A naıve approach is to synchronize all of the updates. This is extremely costly: Haskell programs do a lot of thunk updates! Once again, our saving grace is purity: as thunks represent p ure computation, evaluating a thunk twice has no observable effect: both evaluations are guaranteed to come up with the same result. Thus, we should be able to keep updates to thu nk unsynchronized, at the cost of occasional duplication of work when two threads race to evaluate the same thunk

[...]

4.3 Black holes

Some thunks take a long time to evaluate: we’d like to avoid du plicating their work. What we would like is for threads to notice when someone is working on a thunk, and wait for the result to become available. The mechanism by which this is implemented is a black hole , which represents a thunk that is currently being evaluated. A thunk can be claimed by overwriting it with a black hole. Black holes were originally proposed as a solution for a space leak that occured in some cases of tail calls (Jones, 2008), but they have found th eir utility in a multithreaded setting. Recall that a thread wishing to evaluate a thunk jum ps to the entry code; the entry code of a black hole places a thread on the blocked queue of the owner the black hole, to be woken up when the thunk has been evaluated.

There are two times when a black hole can be written: it can be eagerly written as soon as a thunk is evaluated, or it can be lazily deferred for when a thread has gotten descheduled (and thus the thunk was taking a long time to evaluate.) If a bl ack hole is written eagerly, it is on the fast path of thunk updates, and we cannot use synch ronization. We call these eager black holes (also known as grey holes ), which do not guarantee exclusivity. Lazy blackholing is done more infrequently, and thus we can affor d to use a CAS to implement them.

The upshot is that GHC is able to implement lazy evaluation wi thout any synchroniza- tion for most thunk updates, applying synchronization only when it is specifically neces- sary. The cost of this scheme is low: a single extra field in thu nk and a (rare) duplication of work upon a race [...]

sf ★★★ ()

нужны какие-то механизмы синхронизации. А механизмы синхронизации это уже состояние

я тебе больше скажу: чтобы программа работала, ей нужна оперативная память, а память - это уже состояние

и каждый pthread_create внутри ядра обращается к единой для процесса таблице потоков (или единой для системы таблице задач, в зав-ти от реализации), которые тоже суть состояние

MyTrooName ★★★★★ ()

в хаскелле значит тоже состояние есть, просто оно спрятано языком, и к нему нельзя получить доступ вручную

Всё так. Конкретно по твоему вопросу: когда тред начинает вычислять санк, infoPtr санка перезаписывается и при повторном заходе в него из другого треда, тред лочится. На самом деле немного хитрее, но суть примерно такая.

KblCb ★★★★★ ()
Ответ на: комментарий от sf

А почему не написано, когда происходит это «specifically necessary» в

applying synchronization only when it is specifically neces- sary

?

hlebushek ★★ ()

Ссылочная прозрачность. Ну, вычислишь ты один и тот же thunk дважды или трижды. Разве от этого результат изменится, хотя как тут подсказывают, существует некий механизм от повторных вычислений. Это уровень thunk'ов.

Побочные эффекты, изменяемое состояние и императивные вычисления идут уровнем выше. Там что-то похожее на монаду состояния.

dave ★★★★★ ()
Ответ на: комментарий от nezamudich

Возможные при этом состояния гонки роли не играют, поскольку они на результат выполнения программы в целом влияния не оказывают.

Чего? Такой тупизны ни разу еще не слышал, ты реально чемпион.

lennykravits2015 ()
Ответ на: комментарий от lennykravits2015

Хотел сперва тебя отправить в статьи СПЖ, СМ или хотя бы в бложек к Янгу. Но потом подумал, а чем ты такое снисхождение заслужил?

nezamudich ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.