对于 nim 中的 owlkettle 包(一种声明性 gtk 包装器),我正在研究如何“正确”实现多线程。
为此,我正在研究如何设置客户端-服务器架构。
我知道 nim 在使用 --threads:on 编译时能够运行多线程(或者默认在 nim 2.0 上),所以这应该是可能的。 这个最小的示例展示了一种称为“通道”的机制,但是如何将其变成一个更加基于客户端-服务器的示例,其中两个线程都将继续运行,直到我停止它?
这只需要在两端都有一个小的 while 循环。
以下示例是对上面链接的示例的修改。 一个“前端”线程从终端读取用户输入,并将其发送到“后端”线程,后者可以用它来执行操作。
请注意,您还可以使用对象变体而不是字符串(因此
Channel[YourMessageVariant]
)以允许发送不同类型的消息。
另外作为旁注,以下示例将运行 3 个线程:
import std/[os]
proc setupSender(commChan: var Channel[string]): Thread[ptr Channel[string]] =
proc sendMsg(chan: ptr Channel[string]) =
echo "Type in a message to send to the Backend!"
while true:
let terminalInput = readLine(stdin) # This is blocking, so this Thread doesn't run through unnecessary while-loop iterations unlike the receiver thread
echo "Sending message from frontend from thread ", getThreadId(), ": ", terminalInput
while not chan[].trySend(terminalInput):
echo "Try again"
createThread(result, sendMsg, commChan.addr)
proc setupReceiver(commChan: var Channel[string]): Thread[ptr Channel[string]] =
proc recvMsg(chan: ptr Channel[string]) =
while true:
let response: tuple[dataAvailable: bool, msg: string] = chan[].tryRecv()
if response.dataAvailable:
echo "Received message at Backend on Thread: ", getThreadId(), " :", response.msg
sleep(0) # Reduces stress on CPU when idle, increase when higher latency is acceptable for even better idle efficiency
createThread(result, recvMsg, commChan.addr)
proc main() =
var commChan: Channel[string] # A queue of messages send from one thread to another, can have a pre-defined size
commChan.open() # Must be done before using the channel
let senderThread = setupSender(commChan)
let receiverThread = setupReceiver(commChan)
joinThreads(senderThread, receiverThread)
main()