SILVER HAIRED LISP のスレッド
Java25あたりから導入されたバーチャルスレッド(軽量スレッド)を使っています。
従来のOSスレッドが数千個程度だったのに対して、バーチャルスレッドは100倍近いスレッドを作れるそうです。
簡単なスレッド操作
本Lispの仕様ですが、cl-userのパッケージでは、スレッドを短い名前で使う事が出来ません。
bt: という短い名前で使いたいので、スレッド操作用のパッケージを作ります。
(defpackage :my-thread
(:use :cl :ext)
;; :local-nicknames (ローカルな別名 実際のパッケージ名)
(:local-nicknames (:bt :BORDEAUX-THREADS))
)
my-threadの中だけで、使えるローカルニックネームを付けています。
なお、:local-nicknamesは、CLの仕様にはありませんが、SBCLのような近代的なCL実装では付いているそうです。
(in-package :my-thread)
または
(in-package "my-thread")
警告
たまに、(in-package #:my-thread) こういう書き方を見かけますが、本Lispでは#:という表記を読む事が出来ません。
テスト用の関数を定義
(defun thread-test ()
(let ((threads '()))
(dotimes (i 1000)
(push (bt:make-thread
(lambda () (log-info "~A" (bt:thread-name (bt:current-thread)) )
(print (list "hello from" i ))
)
)
threads))
;; 全部 join
(dolist (a threads)
(bt:thread-join a))
)
)
関数を実行
(thread-test)
途中省略
("hello from" 997)
("hello from" 998)
("hello from" 999)
("hello from" 1000)
nil
io.github.shlisp.objects.Nil
thread-testの中で使われている、log-infoという関数は、本Lispの独自関数です。
windowsの環境で、 .\winshl.cmd で、本インタープリタを起動した際、2つの窓が開くと思いますが
片方の窓は、ログを表示しています。
16:57:12.507 [lisp-make-thread-992] I i.g.s.f.LogInfoFn - lisp-make-thread-992
16:57:12.507 [lisp-make-thread-993] I i.g.s.f.LogInfoFn - lisp-make-thread-993
16:57:12.507 [lisp-service-1] I i.g.s.l.MakeThreadFun - VirtuslThread start : id = 1057, name = lisp-make-thread-994
16:57:12.507 [lisp-make-thread-994] I i.g.s.f.LogInfoFn - lisp-make-thread-994
16:57:12.507 [lisp-service-1] I i.g.s.l.MakeThreadFun - VirtuslThread start : id = 1058, name = lisp-make-thread-995
16:57:12.507 [lisp-make-thread-995] I i.g.s.f.LogInfoFn - lisp-make-thread-995
16:57:12.507 [lisp-service-1] I i.g.s.l.MakeThreadFun - VirtuslThread start : id = 1059, name = lisp-make-thread-996
16:57:12.507 [lisp-make-thread-996] I i.g.s.f.LogInfoFn - lisp-make-thread-996
16:57:12.507 [lisp-service-1] I i.g.s.l.MakeThreadFun - VirtuslThread start : id = 1060, name = lisp-make-thread-997
16:57:12.507 [lisp-make-thread-997] I i.g.s.f.LogInfoFn - lisp-make-thread-997
16:57:12.507 [lisp-service-1] I i.g.s.l.MakeThreadFun - VirtuslThread start : id = 1061, name = lisp-make-thread-998
16:57:12.507 [lisp-make-thread-998] I i.g.s.f.LogInfoFn - lisp-make-thread-998
16:57:12.507 [lisp-service-1] I i.g.s.l.MakeThreadFun - VirtuslThread start : id = 1062, name = lisp-make-thread-999
16:57:12.507 [lisp-make-thread-999] I i.g.s.f.LogInfoFn - lisp-make-thread-999
時刻の次に表示されている [lisp-make-thread-XXX] の部分がスレッド名です。
ログを見ると実際に1000作成されている事が確かめられます。
Javaのバーチャルスレッド(軽量スレッド)は、本当に軽いので1000個のスレッド作成をインタープリタで実行しても一瞬で終わってしまいます。
Java25以降あたりから、新規にスレッドのプログラムを作る際は、バーチャルスレッドが推奨されています。
そのため、本Lispでは、バーチャルスレッドのみを扱う事にしました。
大抵のユースケースでは、バーチャルスレッドの方が優れています。
従来の スレッド(OSスレッド)の方が優れている事も、たまにあるそうです。
WebサーバーのようなIO待ちが大量に発生するケースや、HTTPクライアントのように待ちが発生するケースではスレッドを使った方が良いそうです。
CPUバウンダリーな処理の場合、スレッドにしても、速くならないそうです。
画面に表示された ("hello from" 1000)の部分が、キレイに1から1000まで並んでいない事があります。
これは上記のテストプログラムを動かした場合の仕様だそうです。SBCLで実行した場合もキレイに1から1000まで並ばないとAIに教えてもらいました。
感想
「従来のOSスレッドでは、スレッドプールを作って、キューにためて、順次処理する」といった手法が必要で、コーディングもなかなか大変でした。
バーチャルスレッド(軽量スレッド)では、 『 スレッドプールを作る必要すらありません 』 。
スレッドは【気軽に作っては捨て】の、使い捨ての時代になりました!
さすがJavaです。Java25最高です!!