Respostas:
Eu recomendo fortemente "The Joy of Clojure" ou "programming Clojure" para uma resposta real a esta pergunta, posso reproduzir um pequeno recorte das motivações para cada um:
comece assistindo este vídeo sobre a noção de Identidade e / ou estudando aqui .
O acesso coordenado é usado quando duas identidades precisam ser alteradas juntas, o exemplo clássico é mover dinheiro de uma conta bancária para outra, ele precisa ser movido completamente ou não.
O acesso não coordenado é usado quando apenas uma identidade precisa ser atualizada, este é um caso muito comum.
O acesso síncrono é usado quando se espera que a chamada espere até que todas as identidades tenham sido estabelecidas antes de continuar.
O acesso assíncrono é "dispare e esqueça" e deixe a Identidade atingir seu novo estado em seu próprio tempo.
ensure
função: clojure.github.io/clojure/clojure.core-api.html#clojure.core/… para tornar isso explícito e mais eficiente.
Refs são para estados que precisam ser sincronizados entre os threads. Se você precisa acompanhar um monte de coisas diferentes e às vezes precisa fazer operações que gravam em várias coisas de uma vez, use refs. Sempre que você tiver vários estados diferentes, usar referências não é uma má ideia.
Os átomos são para estados independentes que precisam ser sincronizados entre os threads. Se você nunca precisará mudar o estado do átomo e qualquer outra coisa ao mesmo tempo, usar at atom é seguro (em particular, se houver apenas um pedaço de estado em todo o programa, você pode colocá-lo em um átomo) . Como um exemplo não trivial, se você está tentando armazenar em cache os valores de retorno de uma função (ou seja, memorizá-la), usar um átomo provavelmente é seguro - o estado é invisível para tudo fora da função, então você não precisa se preocupar sobre uma mudança de estado dentro da função bagunçando alguma coisa.
O ponto principal dos agentes é que eles são executados em um segmento diferente. Você pode obter o valor do agente e dizer a ele para aplicar uma função a seu valor, mas não sabe quando a função será executada ou a qual valor a função será aplicada.
Vars são para quando você precisa armazenar algo por thread. Se você tiver um programa multi-threaded e cada thread precisa de seu próprio estado privado, coloque esse estado em uma var.
No que diz respeito aos exemplos do mundo real, se você fornecer um exemplo do que está tentando fazer, podemos dizer o que usar.
Quando li pela primeira vez sobre esses tipos, também tive dificuldade para entender onde poderia ou deveria usar cada um, então aqui está minha resposta simples em inglês:
Use uma var quando os dados não mudarem. Isso acontece sempre que você usa def
ou a maioria das funções que começam com def
like defn
.
Use um átomo quando você tiver um único item que muda. Um exemplo pode ser um contador ou vetor ao qual você deseja adicionar itens.
Use um ref quando você tiver duas ou mais coisas que devem mudar ao mesmo tempo. Pense em "transações de banco de dados" se você estiver familiarizado. O exemplo canônico disso é a transferência de dinheiro de uma conta para outra. Cada conta pode ser armazenada em um ref para que as alterações possam ser feitas para parecerem atômicas.
Use um agente quando quiser que algo mude, mas não se importa quando. Isso pode ser um cálculo longo ou escrever algo em um arquivo ou socket. Observe que com o último você deve usar send-off
.
Nota: Eu entendo que há muito mais em cada um deles, mas espero que isso seja um ponto de partida.
Escrevi artigo com resumo da diferença entre eles e ajudo a escolher quando usar qual deles.
Compartilhar estado - quando usar vars, atoms, agents e refs?
Espero que ajude as pessoas que procuram respostas nesse tópico.
Alguns atalhos do artigo após a sugestão de @tunaci:
Vars
Vars são globais para todos os tópicos.
Não mude vars após criar. É tecnicamente possível, mas é uma má ideia por vários motivos.
Átomos
Compartilhe o acesso ao estado mutável para todos os threads. A mudança ocorre de forma síncrona. Tente novamente quando outro encadeamento mudar de estado durante a execução.
Não use funções não idempotentes e funções com longa execução
Agentes
Compartilhe o acesso ao estado mutável para todos os threads. A mudança ocorre de forma assíncrona.
Refs
Refs funciona de forma semelhante às transações do banco de dados. A gravação e a leitura são protegidas no dosync. Você pode operar em muitos refs com segurança na transação.
E fluxograma quando usar qual:
Veja a imagem no site, pois algumas atualizações sempre são possíveis.
É complexo e um tópico longo para dar uma resposta completa sem uma cópia do artigo anterior, então, por favor, me perdoe, eu redireciono você para o site :)
átomos, referências e agentes - alguma iluminação aqui http://blog.jayfields.com/2011/04/clojure-state-management.html
state-a
, mas consultar aostate-b
fazer isso, ainda preciso de umref
correto? Então, não está mudando várias coisas, mas se referindo a várias coisas enquanto muda qualquer uma delas?