<p>首先,应不惜一切代价避免使用信号:</p>
<p>1)可能导致僵局。SIGALRM可能在阻塞系统调用之前到达进程(想象一下系统中的超高负载!)系统调用不会被中断。僵局。</p>
<p>2)玩弄信号可能会产生一些恶劣的非本地后果。例如,其他线程中的系统调用可能会被中断,这通常不是您想要的。通常系统调用在收到(不是致命的)信号时重新启动。设置信号处理程序时,它会自动关闭整个进程或线程组的此行为。看看上面的“男人信号中断”。</p>
<p>相信我-我以前遇到过两个问题,它们一点都不好玩。</p>
<p>在某些情况下,可以明确地避免阻塞——我强烈建议使用select()和friends(在Python中选中select模块)来处理阻塞的写入和读取。但这无法解决阻塞open()调用。</p>
<p>为此,我已经测试了这个解决方案,它对命名管道很有效。它以非阻塞方式打开,然后将其关闭,如果没有可用的内容,则使用select()调用最终超时。</p>
<pre><code>import sys, os, select, fcntl
f = os.open(sys.argv[1], os.O_RDONLY | os.O_NONBLOCK)
flags = fcntl.fcntl(f, fcntl.F_GETFL, 0)
fcntl.fcntl(f, fcntl.F_SETFL, flags & ~os.O_NONBLOCK)
r, w, e = select.select([f], [], [], 2.0)
if r == [f]:
print 'ready'
print os.read(f, 100)
else:
print 'unready'
os.close(f)
</code></pre>
<p>用以下方法测试:</p>
<pre><code>mkfifo /tmp/fifo
python <code_above.py> /tmp/fifo (1st terminal)
echo abcd > /tmp/fifo (2nd terminal)
</code></pre>
<p>通过一些额外的努力,select()调用可以用作整个程序的主循环,聚合所有事件-您可以使用libev或libevent,或者使用一些Python包装器来包装它们。</p>
<p>当你不能明确地强制非阻塞行为时,比如说你只是使用一个外部库,那么它将变得更加困难。线程可以做到,但显然它不是一个最先进的解决方案,通常是错误的。</p>
<p>恐怕一般来说,你不能用一种强有力的方法来解决这个问题——这真的取决于你阻止了什么。</p>