我正逐渐接近能够通过SBCL读取和写入后台进程的命名管道。我所做的就是启动我想要读/写的程序:
todd@ubuntu:~/CoreNLP$ cat ./spin | /usr/bin/java -cp "*" -Xmx2g edu.stanford.nlp.pipeline.StanfordCoreNLP -annotators tokenize,ssplit,pos,lemma,ner,parse,dcoref -outputFormat text > ./spout &
[1] 24616
所以一切正常,所以我开始SBCL并执行此操作:
(defparameter from-corenlp (open "./spout"))
这也很好,但声明流导致SBCL将流溢出到屏幕上(这是后台进程中的所有启动信息)。它不会等到我从流中读取。事情是如何运作的?
答案 0 :(得分:2)
解决方案,因为我将它发布到stanford解析器邮件列表(堆栈溢出重新格式化了很多奇怪的东西,但你得到了想法):
花了很长时间,但我终于想出了在SBCL Lisp中嵌入(大部分)CoreNLP程序(在交互模式下)。
首先,忘记使用(sb-ext:run-program ...)
。产生Java与引用参数(如星号)的组合,无论转发得多好,都会导致生成的程序崩溃。
Innexior shell似乎启动了解析器,但它只适用于一次性解析,即使在交互模式下也是如此。也许我本可以做得更好,但是需要安装劣质外壳并且记录很差。
使用Unix命名管道的最初尝试解决方案最终成为最后一个,但它需要一些工作,首先是缓冲,然后是操作的顺序,最后了解解析器程序的一些细微差别。
首先,在运行程序时完全关闭缓冲非常重要,因此运行它看起来像这样:
stdbuf --i=0 --o=0 --e=0 cat ./spin | /usr/bin/java -cp "*" -Xmx2g edu.stanford.nlp.pipeline.StanfordCoreNLP -annotators tokenize,ssplit,pos,lemma,ner,parse,dcoref -outputFormat text > ./spout &
这应该是在后台运行解析器接受来自spin的输入并将其输出发送到spout。但是如果你看一下Linux中的进程表,你就不会看到它在运行。它仍在等待从输出管道拉出来之后才能运行。
因此,我们运行SBCL并从解析器的管道启动一个流:
(defparameter *from-corenlp* (open "./spout"))
现在解析器开始运行。奇怪的是,它也开始将输出转储到屏幕,而不是管道!这是因为当解析器启动和停止时(显然甚至是NLP>提示符)的所有这些横幅内容都被发送到stderr,而不是stdout。这实际上是件好事。
然后我们将Lisp的流声明为解析器:
(defparameter *to-corenlp* (open "./spin" :direction :output :if-exists :append))
然后我们发送一些解析器的文本来解析:
(write-line "This is the first test." *to-corenlp*)
我在这里碰到了几次问题,甚至。请记住,Lisp有自己的缓冲区,因此您每次都必须清除流:
(finish-output *to-corenlp*)
然后,您可以在很多次下面运行此行,以验证您是否获得了从解析器的交互式会话中获得的完全相同的行为:
(format t "~a~%" (read-line *from-corenlp*))
如果你是一个好孩子的侦察员,那不仅应该是真的,而且只要你愿意,你就可以继续你的交互式奴隶解析器会话:
(write-line "This is the second test." *to-corenlp*)
(finish-output *to-corenlp*)
这不是很棒吗?请注意,我把所有这些都搞砸了,在Unix上很可怕,在Lisp上很糟糕,并且是一个可怕的童子军!
现在你也可以!