十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
在了解了Linux的信号基础之 后,Python标准库中的signal包就很容易学习和理解。signal包负责在Python程序内部处理信号,典型的操作包括预设信号处理函数,暂 停并等待信号,以及定时发出SIGALRM等。要注意,signal包主要是针对UNIX平台(比如Linux, MAC OS),而Windows内核中由于对信号机制的支持不充分,所以在Windows上的Python不能发挥信号系统的功能。
成都创新互联公司专业为企业提供南阳网站建设、南阳做网站、南阳网站设计、南阳网站制作等企业网站建设、网页设计与制作、南阳企业网站模板建站服务,10年南阳做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
信号(signal)-- 进程之间通讯的方式,是一种软件中断。一个进程一旦接收到信号就会打断原来的程序执行流程来处理信号。
定义信号名
signal包定义了各个信号名及其对应的整数,比如:
import signal
print(signal.SIGABRT)
print(signal.SIG_DFL)
Python所用的信号名与Linux一致,可以通过$ man 7 signal 查询
预设信号处理函数
signal包的核心是使用signal.signal()函数来预设(register)信号处理函数,如下所示:
singnal.signal(signalnum, handler)
signalnum为某个信号,handler为该信号的处理函数。我们在信号基础里提到,进程可以无视信号,可以采取默认操作,还可以自定义操作。当handler为signal.SIG_IGN时,信号被无视(ignore)。当handler为singal.SIG_DFL,进程采取默认操作(default)。当handler为一个函数名时,进程采取函数中定义的操作。
import signal
# Define signal handler function
def myHandler(signum, frame):
print('I received: ', signum)
# register signal.SIGTSTP's handler
signal.signal(signal.SIGTSTP, myHandler)
signal.pause()
print('End of Signal Demo')
# 有问题待测试
在主程序中,我们首先使用signal.signal()函数来预设信号处理函数。然后我们执行signal.pause()来让该进程暂停以等待信号, 以等待信号。当信号SIGUSR1被传递给该进程时,进程从暂停中恢复,并根据预设,执行SIGTSTP的信号处理函数myHandler()。 myHandler的两个参数一个用来识别信号(signum),另一个用来获得信号发生时,进程栈的状况(stack frame)。这两个参数都是由signal.singnal()函数来传递的。
上面的程序可以保存在一个文件中(比如test.py)。我们使用如下方法运行:
$python test.py
以便让进程运行。当程序运行到signal.pause()的时候,进程暂停并等待信号。此时,通过按下CTRL+Z向该进程发送SIGTSTP信号。我们可以看到,进程执行了myHandle()函数, 随后返回主程序,继续执行。(当然,也可以用$ps查询process ID, 再使用$kill来发出信号。)
(进程并不一定要使用signal.pause()暂停以等待信号,它也可以在进行工作中接受信号,比如将上面的signal.pause()改为一个需要长时间工作的循环。)
我们可以根据自己的需要更改myHandler()中的操作,以针对不同的信号实现个性化的处理。
定时发出SIGALRM信号
一个有用的函数是signal.alarm(),它被用于在一定时间之后,向进程自身发送SIGALRM信号:
import signal
# Define signal handler function
def myHandler(signum, frame):
print("Now, it's the time")
exit()
# register signal.SIGALRM's handler
signal.signal(signal.SIGALRM, myHandler)
signal.alarm(5)
while True:
print('not yet')
我们这里用了一个无限循环以便让进程持续运行。在signal.alarm()执行5秒之后,进程将向自己发出SIGALRM信号,随后,信号处理函数myHandler开始执行。
发送信号
signal包的核心是设置信号处理函数。除了signal.alarm()向自身发送信号之外,并没有其他发送信号的功能。但在os包中,有类似于linux的kill命令的函数,分别为
os.kill(pid, sid)
os.killpg(pgid, sid)
分别向进程和进程组(见Linux进程关系)发送信号。sid为信号所对应的整数或者singal.SIG*。
实际上signal, pause,kill和alarm都是Linux应用编程中常见的C库函数,在这里,我们只不过是用Python语言来实现了一下。实际上,Python 的解释器是使用C语言来编写的,所以有此相似性也并不意外。此外,在Python 3.4中,signal包被增强,信号阻塞等功能被加入到该包中。我们暂时不深入到该包中。
总结
signal.SIG*
signal.signal()
signal.pause()
signal.alarm()
ubuntu下,也就是linux下,通常会用kill -事件编号实现。 你查一下LINUX下的事件就明白了。 kill进程号 实现上是发了一个信号给指定的进程。 在python里,也可以加载事件处理模块,处理来自其它程序发过来的信号, 当然你可以用KILL工具发信号...
在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
使用subprocess包中的函数创建子进程的时候,要注意:
1) 在创建子进程之后,父进程是否暂停,并等待子进程运行。
2) 函数返回什么
3) 当returncode不为0时,父进程如何处理。
subprocess.call()
父进程等待子进程完成
返回退出信息
subprocess.check_call()
父进程等待子进程完成
返回0
检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性,可用try...except...来检查。
subprocess.check_output()
父进程等待子进程完成
返回子进程向标准输出的输出结果
检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性和output属性,output属性为标准输出的输出结果,可用try...except...来检查。
这三个函数的使用方法相类似,我们以subprocess.call()来说明:
import subprocess
rc = subprocess.call(["ls","-l"])
实际上,我们上面的三个函数都是基于Popen()的封装(wrapper)。这些封装的目的在于让我们容易使用子进程。当我们想要更个性化我们的需求的时候,就要转向Popen类,该类生成的对象用来代表子进程。
与上面的封装不同,Popen对象创建后,主程序不会自动等待子进程完成。我们必须调用对象的wait()方法,父进程才会等待 (也就是阻塞block):
import subprocess
child = subprocess.Popen(["ping","-c","5",""])
child.wait()
print("parent process")
此外,你还可以在父进程中对子进程进行其它操作,比如我们上面例子中的child对象:
child.poll() # 检查子进程状态
child.kill() # 终止子进程
child.send_signal() # 向子进程发送信号
child.terminate() # 终止子进程
因此,如果不希望当前进程被阻塞,你可以使用Popen对象进行操作。
可以。
在pyqt5编程过程中,经常会遇到输入或选择多个参数的问题,把多个参数写到一个窗口中,主窗口会显得很臃肿,所以,一般是添加一个按钮,调用对话框,在对话框中进行参数的选择,关闭对话框将参数返回给主窗口
pyqt提供了一些标准的对话框类,用于输入数据,修改数据,更改应用的设置等,常见的有QFileDialog,QInputDialog,QColorDialog, QFontDialog等,在不同的窗口之间传参数有两种常用的方式,一种在自定义对话框之间通过属性传参,另一种在窗口之间使用信号与槽机制传参,这里主要介绍第一种
单一窗口的数据传递实例
对于具有单一窗口的程序来说,一个控件的变化会影响另一个控件的变化,这中变化利用信号与槽的关系非常容易解决
答: 你讲的这个是pyqt里面的内容,刚好我最近也一直在学,在代码当中确实没有显式调用这个函数,但是你要知道, keyPressEvent是一个槽函数,在系统内部定义了这个函数,但是里面没有任何代码,而你就是对它重写了,就是说,只要你的键盘里面的任何一个键按下,就相当于会发送一个信号,那么在内部就会自动调用这个函数。类似的函数还有 keyReleaseEvent(键位松开时自动触发)等。希望可以帮助到你。
相关介绍
pyqt的线程之间的通信是通过信号to槽来实现的,首先你在线程类里面声明一个全局槽比如:
class imThread(QtCore.QThread):
imslot = QtCore.pyqtSignal()
这里是要重点注意,上面的是没有任何参数的一个信号,如果你需要参数的话,你可以在里面添加参数类型,例如:
imslot1 = QtCore.pyqtSignal(str) #这是一个带字符串参数的信号
imslot2 = QtCore.pyqtSignal(int) #这是一个带整型参数的信号
imslot3 = QtCore.pyqtSignal(bool) #这是一个带布尔参数的信号
当然了,如果你需要多个参数的话,同样地往里面加就是了,qt也没有要求参数必须是同类型的,所以可以这样:
imslot1 = QtCore.pyqtSignal(str, int) #这是一个带整型和字符串的参数信号
imslot2 = QtCore.pyqtSignal(int, str, str) #这是一个带整型和两个字符串的参数信号
imslot3 = QtCore.pyqtSignal(bool, str) #这是一个带布尔和字符串的参数信号
在线程的run方法里面来定义执行信号:
self.imslot.emit()
这里也是需要重点注意的是,上面这个接口是没有参数的,如果你是要参数的话,是需要这样写:
self.imslot1[str].emit('hello')
self.imslot2[int].emit(1)
self.imslot3[bool].emit(False)
多参数的是这样
self.imslot1[str, int].emit('hello', 1)
self.imslot2[int, str, str].emit(1, "hello", "world")
self.imslot3[bool, str].emit(False, 'hello')
以上就是在线程类里面完成信号定义了,接下来就是逻辑层成定义一个函数槽来连接线程类里面的信号,这个也很简单,比如我在主线程类里面定义一个方法:
def imSlot():
print 'ok'
以上这个是槽函数,接下来是实现信号槽的连接
imThread.imslot.connect('imSlot')
这个就是信号槽的连接方式,当然了,这个是没有参数的一个信号槽,那么带参数的怎么写呢?也很简单!首先定义一个槽函数:
def imSlot(para):
print para
这个是带参数的槽函数,下面是:
imThread.imslot[str].connect('imSlot')
以上就是线程之间的方法了,子线程在执行的通行经过执行信号的话,子线程可以安全地执行而不会出现GUI主线程卡死的情况了。