Python多线程编程之线程守护、变量共享

1.线程守护线程

守护线程是指程序执行完毕后,无论是否执行过,该线程都会被强制终止。
通常,不重要的线程被安装为守护线程。

代码示例如下所示:

importthreadingimporttimedefrun(n):time.sleep(3)print('task',n)defmain():t1=threading.Thread(target=run,args=('t1',))t1.setDaemon(True)t1.start()print('end')if__name__=='__main__':main()

结果:

D:\software\python\python.exeD:/python_record/thread_api_demo.pyendProcessfinishedwithexitcode0

这是因为线程t1是守护线程。
当主线程已经发出end,但线程t1还没有结束时,只能强制终止。
因此,在最终输出t1

2中看不到预期的任务。
线程共享全局变量

线程共享全局变量使用global来定义线程执行的函数中的全局变量。
允许线程从程序中读取和改变全局变量的值,以达到线程间共享全局变量的目的。

importthreadingg_num=100defwork1():globalg_numfor_inrange(3):g_num+=1print('inwork1g_numis:%d'%g_num)defwork2():globalg_numfor_inrange(3):g_num-=3print('inwork2g_numis:%d'%g_num)defmain():t1=threading.Thread(target=work1)t2=threading.Thread(target=work2)t1.start()t2.start()if__name__=='__main__':main()

结果:

inwork1g_numis:103inwork2g_numis:94

Pyqt5如何停止多线程

下面展示了如何使用signal/slot信号槽退出线程的简单示例。

如果有按钮,单击可启动线程,再次单击可退出线程。
该线程的任务是打印a(1-20),然后打印b(1-20),代码如下:

[python]viewplaincopy

classUpdateThread(QThr)。
ead):

def__init__(self,parent=None):

super(UpdateThread,self).__init__(parent)

self.flag=1#使用到判断循环是否继续,改变标志退出线程中的run函数

defrun(self):

table=['a','b','c','d','e',​​​​​'f','g']

对于范围(6)中的i:

如果self.flag==1:

打印表[i]

forminrange(20):

打印m

time.sleep(0.5)

else:

break

print'close'#输出表明线程执行函数已经终止

defstop(self):

打印'设置标志为假'

self.flag=0

printself.flag

由于Python线程本来就没有线程退出API,所以了解到QThread有API来实现线程阻塞、退出、强制退出等,所以thread继承了QThread,但是在GUI界面按钮逻辑中写入mythread.wait()或quit()或terminate()并不能影响线程。
影响(可能是因为当时没有使用信号和槽机制,所以没有起作用)然后自己写一个stop函数来改变线程中的一个flag来停止execute函数中的循环。
然后如上面代码所示,在按钮逻辑中写入如下内容(错误演示):

[.python]viewplaincopy

defupdate_db():#错误

self.new_thread1=UpdateDbThread()

ifself.update_tag==0:

self.update_tag=1

self.new_thread1.start()

其他:

self.update_tag=0

self.new_thread1.stop()

执行后发现stop函数改变了elf.flag的值,但是判断语句中flag的值循环仍然是1,并且循环没有停止。
然后我查了资料,去Stackoverflow找答案线程需要通过信号和槽机制来响应。
因此,检查qt的相关信号/槽信息,修改关键代码如下:

[python]viewplaincopy

classmywidget(Qwidget):

sin=pyqtSignal()#提前声明

def__init__(self):

...

self.new_thread1=UpdateDbThread()

self.sin.connect(self.new_thread1.stop)

defupdate_db():

ifself.update_tag==0:

self.update_tag=1

self.new_thread1.start()

其他:

self.更新标签=0

self.sin.emit()

[python]viewplain复制

pyqtSignal信号的定义既不能写在update_db方法中,也不能写在init()初始化方法中,原因如下(来自stackoverflow):

所以我们在init-Method之前定义Type是一个很好的方法sin和set的信号然后连接到线程的stop方法。
单击发送信号按钮会更改线程的标志,然后退出循环。
运行结果如下:

为了更方便映射,我将循环输出改为10:

线程正常终止,目标达到。
您可以选择执行方式根据自己的需要重写。

还有一点需要注意的是,方法中不能写mythread=update_db(),否则运行时会报错,运行时threadisrunning会被销毁,因为mythread是方法中的局部变量,当方法结束时,Python的垃圾回收机制会自动销毁,就会出现上述错误。
因此,需要在mythread前添加self,使线程成为全局变量。

pythony中子进程如果一定时间不结束就停止应该如何做?

如果要使用thread模块,需要在主线程中休眠一段时间。
如果子流程没有完成,只要进入主流程下面的代码,子流程就会自动完成。
当然,这也是Thread模块的一个缺点。
无论子进程是否退出,只要主线程继续运行,所有子线程都会被杀死。
如果使用的是threading模块,那么除非将子线程设置为守护进程,否则子线程将在主线程执行完毕后被杀死。
你的问题有点奇怪。
还有人问如何防止子线程在主线程执行时被杀死。





举个例子:importthreadfromtimeimportsleep,ctimedefloop0():print'startloop0at:',ctime()sleep(4)print'loop0doneat:',ctime()defloop1():print'startloop1at:',ctime()sleep(2)print'loop1doneat:',ctime()defmain():print'startingat:',ctime()thread.start_new_thread(loop0,())thread.start_new_thread(loop1,())sleep(6)print'allDONEat:',ctime()if__name__=='__main__':main()这是一个示例基本的Python编程。
主线程将等待6秒。
6秒后会继续打印“allDoneat:”,主程序(即主线程)中的ctime.()子线程无论完成与否都会被销毁。