Common lisp SBCL中输入管道的读取困难

Common lisp SBCL中输入管道的读取困难,common-lisp,stanford-nlp,named-pipes,sbcl,Common Lisp,Stanford Nlp,Named Pipes,Sbcl,我正慢慢地接近能够通过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 & [

我正慢慢地接近能够通过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将流溢出到屏幕上(这是后台进程的所有启动信息)。它不会等到我从流中读取。事情应该是这样的吗

解决方案,正如我将其发布到stanford parser邮件列表(stack overflow将它的许多内容重新格式化为一些奇怪的内容,但您明白了):

这花了相当长的时间,但我最终找到了在SBCLLISP中嵌入(大部分)CoreNLP程序(在交互模式下)的方法

首先,忘记使用
(sbext:runprogram…
)。无论转义得有多好,生成Java与带引号的参数(如星号)的组合只会使生成的程序崩溃

次等shell似乎启动了解析器,但它仅适用于一次性解析,即使在交互模式下也是如此。也许我本可以做得更好,但需要安装劣质的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))
(format t "~a~%" (read-line *from-corenlp*))
然后我们发送一些文本供解析器解析:

(write-line  "This is the first test." *to-corenlp*)
我甚至在这里遇到过几次问题。请记住,Lisp有自己的缓冲区,因此每次都必须清除流:

(finish-output *to-corenlp*)
然后,您可以在下面运行这行代码很多次,以验证您是否获得了与从解析器的交互式会话中获得的行为完全相同的行为:

(defparameter *to-corenlp* (open "./spin" :direction :output :if-exists :append))
(format t "~a~%" (read-line *from-corenlp*))
如果您是一名优秀的童子军,这不仅应该是正确的,而且您可以继续您的交互式从属解析器会话,只要您愿意:

(write-line  "This is the second test." *to-corenlp*)
(finish-output *to-corenlp*)
那不是很棒吗?注意,我在Unix上表现糟糕,在Lisp上表现糟糕,而且还是个糟糕的童子军


现在你也可以了

解决方案,正如我将其发布到stanford parser邮件列表(stack overflow将它的许多内容重新格式化为一些奇怪的内容,但您明白了):

这花了相当长的时间,但我最终找到了在SBCLLISP中嵌入(大部分)CoreNLP程序(在交互模式下)的方法

首先,忘记使用
(sbext:runprogram…
)。无论转义得有多好,生成Java与带引号的参数(如星号)的组合只会使生成的程序崩溃

次等shell似乎启动了解析器,但它仅适用于一次性解析,即使在交互模式下也是如此。也许我本可以做得更好,但需要安装劣质的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))
(format t "~a~%" (read-line *from-corenlp*))
然后我们发送一些文本供解析器解析:

(write-line  "This is the first test." *to-corenlp*)
我甚至在这里遇到过几次问题。请记住,Lisp有自己的缓冲区,因此每次都必须清除流:

(finish-output *to-corenlp*)
然后,您可以在下面运行这行代码很多次,以验证您是否获得了与从解析器的交互式会话中获得的行为完全相同的行为:

(defparameter *to-corenlp* (open "./spin" :direction :output :if-exists :append))
(format t "~a~%" (read-line *from-corenlp*))
如果您是一名优秀的童子军,这不仅应该是正确的,而且您可以继续您的交互式从属解析器会话,只要您愿意:

(write-line  "This is the second test." *to-corenlp*)
(finish-output *to-corenlp*)
那不是很棒吗?注意,我在Unix上表现糟糕,在Lisp上表现糟糕,而且还是个糟糕的童子军


现在你也可以了

“事情应该是这样的吗?”不。使用“cat/dev/random>fifo”(用mkfifo制作的fifo)和从sbcl打开fifo的简单测试不允许我复制这个问题。关于这件事,你还有什么可以告诉我们的吗?好吧,我想这不应该是这样的。我在一个文件中做了一个cat测试,输出结果在lisp管道中得到了可靠的验证。声明输出流fr