- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
考虑这个小的 python 脚本 odd-read-blocking.py
:
#!/usr/bin/python
import signal
import sys
sig = None
def handler(signum, frame):
global sig
sig = signum
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)
x = sys.stdin.read(3)
print 'signal', sig
print 'read bytes', len(x)
exit(0)
我运行它并向它提供两个字节的标准输入数据 ('a' + '\n'):
> echo a | ./odd-read-blocking.py
signal None
read bytes 2
>
很好。
现在我用相同的两个字节输入它(通过在其标准输入中键入 'a' + '\n')。请注意,标准输入还没有到达 EOF,并且可能会有更多数据到来。所以读取 block ,因为它期望多一个字节。我在脚本上使用 Ctrl+C。
> ./odd-read-blocking.py
a
^Csignal 2
read bytes 2
>
很好。我们看到已经读取了两个字节并收到了信号 2。
现在我打开一个标准输入流,但不向其发送任何字节。读取 block 如预期。如果我现在在脚本上使用 Ctrl+C,它会一直坐在那里等待。读取不会中断。 SIGINT 将不会被处理。
> ./odd-read-blocking.py
^C
这里什么都没有。脚本仍在运行(在读取时似乎被阻止)。
现在按回车一次,然后再次按 Ctrl+C:
^Csignal 2
read bytes 1
>
因此,只有在其标准输入上至少接收到一些数据(在本例中为单个“\n”)后,脚本才会按我预期的方式运行并正确中断被阻止的读取并告诉我它已收到信号 2 和读取 1 个字节。
备选方案 1:如上所示,我没有使用 Ctrl+C,而是使用 kill <em>pid</em>
尝试了同样的操作从一个单独的终端。行为相同。
备选方案 2:我没有使用上述的 shell 标准输入,而是这样做了:
> sleep 2000 | ./odd-read-blocking.py
使用 kill <em>pid</em>
时将 SIGTERM 发送到 odd-read-blocking.py
过程我得到相同的行为。这里,脚本进程只能使用SIGKILL(9)来杀死。
为什么读取在一个尚未空但仍处于事件状态的标准输入流上阻塞时没有被中断?
我觉得这很奇怪。谁没有?谁能解释一下?
最佳答案
如果 Python 信号处理程序抛出异常以放弃正在进行的 file.read
,则任何已读取的数据都会丢失。 (任何异步异常,比如默认的 KeyboardInterrupt
,基本上不可能阻止这种故障,除非你有一个 way to mask it。)
为了尽量减少对此的需求,file.read
在被信号中断时提前返回(即,字符串比请求的更短)——注意这除了记录的 EOF 和非阻塞 I/O 案例之外!但是,当它还没有数据时它不能这样做,因为它返回空字符串以指示 EOF。
一如既往,理解这种行为的方法是使用 strace
。
当信号到达而进程被阻塞时,实际的 read
系统调用会进退两难。首先,调用 (C) 信号处理程序——但由于这可能发生在任何两条指令之间,因此除了设置标志(或写入自管道)之外,它几乎无能为力。然后呢?如果设置了SA_RESTART
,则恢复通话;否则……
如果尚未传输任何数据,read
可能会失败,客户端可以检查其信号标志。它无法通过特殊的 EINTR
来澄清 I/O 实际上没有任何问题。
如果一些数据已经写入(用户空间)缓冲区,它不能只返回“失败”,因为数据会丢失——客户端无法知道缓冲区中有多少(如果有的话)数据.所以它只返回成功(到目前为止读取的字节数)!像这样的短读取总是有可能的:客户端必须再次调用 read
以检查它是否已到达文件末尾。 (就像 file.read
一样,0 字节的短读取将 EOF。)因此,客户端必须在每次读取后检查其信号标志,无论是否成功. (请注意,这仍然不是 perfectly reliable ,但对于许多交互式用例来说已经足够了。)
系统调用并不是全部:毕竟,终端的正常配置让它在看到换行符后立即返回。 Python 2 的低级 file.read
是一个 wrapper for fread
, 如果一个很短,它将发出另一个 read
。但是当读取失败并显示 EINTR
时,fread
会提前返回并且 file.read
会调用您的 (Python) 信号处理程序。 (如果你向它添加输出,你会看到它会立即为你发送的每个信号调用,即使 file.read
没有返回。)
然后它面临着与系统调用类似的困境:正如所讨论的,短读不能为空,因为它意味着 EOF。然而,与 C 信号处理程序不同的是,Python 信号处理程序可以执行任意工作(包括引发异常以立即中止 I/O,如开头所述,代价是冒着数据丢失的风险),并且它被认为是对接口(interface)隐藏可能性 EINTR
。所以 fread
调用只是默默地重复。
重试规则changed in 3.5 .现在,即使手头有数据,io.IOBase.read
也会恢复;这更一致,但它 forces使用异常来停止读取,这意味着您不能选择等待某些数据以免丢失您已经拥有的任何数据。非常重量级的解决方案是切换到多路复用 I/O 并使用 signal.set_wakeup_fd()
;这具有允许 SIGINT 影响主线程的额外优势,而不必费心在所有其他线程中屏蔽它。
关于python - 在具有自定义信号处理程序的情况下在 python 2 中读取 sys.stdin 时出现奇怪的阻塞行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49653837/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!