43 votes

Comment démarrer un fil de discussion en Clojure ?

J'ai lu beaucoup de choses sur l'excellence de Clojure en matière de concurrence, mais aucun des tutoriels que j'ai lus n'explique réellement comment créer un thread. Faut-il simplement faire (.start (Thread. func)), ou existe-t-il un autre moyen que j'ai manqué ?

40voto

Brian Carper Points 40078

Clojure fn sont Runnable il est donc courant de les utiliser exactement comme vous l'avez indiqué, oui.

user=> (dotimes [i 10] (.start (Thread. (fn [] (println i)))))
0                                                             
1                                                             
2                                                             
4                                                             
5                                                             
3                                                             
6                                                             
7                                                             
8                                                             
9                                                             
nil

Une autre option consiste à utiliser agents Dans ce cas, vous devez send o send-off et il utilisera un Thread d'un pool.

user=> (def a (agent 0))
#'user/a
user=> (dotimes [_ 10] (send a inc))
nil
;; ...later...
user=> @a
10

Une autre option encore serait pcalls y pmap . Il y a aussi future . Ils sont tous documentés dans le API Clojure .

32voto

mikera Points 63056

Habituellement, lorsque je veux démarrer un fil de discussion dans Clojure, j'utilise simplement futur .

En plus d'être simple à utiliser, cette méthode présente l'avantage d'éviter d'avoir à effectuer une interopérabilité Java désordonnée pour accéder aux mécanismes de threading Java sous-jacents.

Exemple d'utilisation :

(future (some-long-running-function))

Cela permettra d'exécuter la fonction de manière asynchrone dans un autre thread.

(def a (future (* 10 10)))

Si vous voulez obtenir le résultat, il suffit de déréférencer le futur, par ex :

@a
=> 100

Notez que @a se bloque jusqu'à ce que le futur thread ait terminé son travail.

14voto

Carl Smotricz Points 36400

Programmation de Clojure n'aborde pas cette question avant la page 167 : "Utiliser des agents pour les mises à jour asynchrones".

Avant de vous lancer dans des discussions, sachez que Clojure est capable de faire du multitâche tout seul, si on lui en donne l'occasion. J'ai écrit des programmes ignorant allègrement la concurrence et j'ai constaté que lorsque les conditions sont réunies, ils occupent plus d'une unité centrale. Je sais que ce n'est pas une définition très rigoureuse : Je n'ai pas encore exploré ce sujet en profondeur.

Mais pour les occasions où vous avez vraiment besoin d'une activité séparée explicite, l'une des réponses de Clojure est apparemment l'agent.

(agent initial-state)

en créera un. Ce n'est pas comme un thread Java, c'est-à-dire un bloc de code qui attend d'être exécuté. Il s'agit plutôt d'une activité qui attend qu'on lui donne du travail à faire. Pour ce faire, il suffit de

(send agent update-fn & args)

L'exemple fait

(def counter (agent 0))

counter est votre nom et votre identifiant pour l'agent ; l'état de l'agent est le numéro 0.

Une fois cette étape franchie, vous pouvez envoyer votre travail à l'agent :

(send counter inc)

lui dira d'appliquer la fonction donnée à son état.

Vous pouvez ensuite extraire l'état de l'agent en le déréférençant :

@counter vous donnera la valeur actuelle du nombre qui a commencé à 0.

Fonction await vous permettra de faire quelque chose comme un join sur l'activité de l'agent, si elle est longue :

(await & agents) attendra qu'ils soient tous terminés ; il existe aussi une autre version qui prend un délai d'attente.

9voto

Jörg W Mittag Points 153275

Oui, la façon dont vous démarrez un Thread Java dans Clojure est quelque chose comme ce que vous avez là.

Cependant, le réel La question est : pourquoi voulez-vous faire cela ? Clojure a beaucoup de meilleures constructions de concurrence que les threads.

Si vous regardez l'exemple canonique de la concurrence dans Clojure, La simulation de la colonie de fourmis de Rich Hickey vous verrez qu'il utilise exactement 0 fils. La seule référence à java.lang.Thread dans toute la source est de trois appels à Thread.sleep dont le seul but est de ralentir la simulation pour que vous puissiez réellement voir ce qui se passe dans l'interface utilisateur.

Toute la logique est réalisée en Agents : un agent pour chaque fourmi, un agent pour l'animation et un agent pour l'évaporation des phéromones. Le terrain de jeu est un réf. transactionnel. Pas un thread ni un verrou en vue.

2voto

Timothy Pratley Points 3945

L'utilisation d'un futur est généralement l'accès adhoc le plus simple au threading. Cela dépend entièrement de ce que vous voulez faire :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X