Python使用单例跨文件退出子线程

Published: 2017-05-22

Tags: Python

本文总阅读量

(一)终止线程

前一阵做GUI一些按钮功能耗时较长,会导致GUI无响应,所以把按钮功能放到了线程去做,有一个按钮点击后建立socket连接监听服务端的信息,再次点击按钮断开socket连接

于是就遇到了这个问题,使用线程开启的监听无法通过按钮退出线程,琢磨了一下想到一个办法,原先是用线程B启动socket任务,现在为了实现退出线程的功能,设置一个全局变量,然后使用线程A启动线程B,A启动B后每隔0.2s检查一下全局变量,当全局变量变化时退出线程,这样,B作为A的子线程也就会跟着退出,B线程启动时需要指定(thread.daemon = True)

PS:说下thread.daemon,当其为True时,父进(线)程退出子线程也跟着退出,这是默认值,当其为False时,父线程执行完毕后子线程不退出依旧运行,终端上运行的表现就是程序Ctrl+C不能终止程序

(二)跨文件全局变量

问题得到了解决,不过紧接着遇到了另一个问题。 当我把功能封装成模块后,子线程不能找到这个全局变量了,也就是说python中的全局变量是相对于文件来说的,跨文件就不行了

好在之前了解过python单例,下面是一个使用模块实现单例的例子

import sys

class Count(object):
    def __init__(self):
        print "init count"
        self.a = 0
    def up(self):
        print "+1"
        self.a = self.a + 1
    def down(self):
        print "-1"
        self.a = self.a - 1

sys.modules[__name__] = Count()


''' python使用模块实现单例模式 '''

# 使用方法如下:

# [GCC 6.1.1 20160621 (Red Hat 6.1.1-3)] on linux2
# Type "help", "copyright", "credits" or "license" for more information.
# >>> import Count
# init count
# >>> Count.up()
# +1
# >>> Count.a
# 1
# >>> Count.up()
# +1
# >>> Count.a
# 2
# >>>

单例,只初始化一次,且不同文件导入的都是同一个对象,用法简单,正好可以完美解决多文件共享全局变量的问题,经过测试,证明了我的猜测

(三)Demo

.
├── global_flag.py
├── __init__.py
├── main.py
└── tools.py

0 directories, 4 files

main.py

#!/bin/env python

from tools import print_datetime, print_datetime_parent, \
                  print_datetime_with_thread

import global_flag
import time


def main():

    '''
    main function
    '''

    print_datetime_with_thread()

    time.sleep(1)
    print('execute me')

    time.sleep(10)
    print('main 10s after')

    global_flag.change()


if __name__ == '__main__':

    main()

tools.py

# -*- coding: utf-8 -*-

from threading import Thread
from time import strftime
import time
import global_flag


def print_datetime():

    while True:
        print(strftime('[%Y-%m-%d %H:%M:%S]'))
        time.sleep(1)


def print_datetime_parent():

    thread = Thread(target=print_datetime)
    thread.daemon = True
    thread.start()

    while True:

        if global_flag.get():
            return

        time.sleep(0.2)


def print_datetime_with_thread():

    thread = Thread(target=print_datetime_parent)
    thread.daemon = True
    thread.start()

global_flag.py

import sys

class global_flag(object):

    def __init__(self):
        self.flag_value = False
    def get(self):
        return self.flag_value
    def change(self):
        self.flag_value = not self.flag_value

sys.modules[__name__] = global_flag()

output

[2017-05-20 17:12:29]
execute me
 [2017-05-20 17:12:30]
[2017-05-20 17:12:31]
[2017-05-20 17:12:32]
[2017-05-20 17:12:33]
[2017-05-20 17:12:34]
[2017-05-20 17:12:35]
[2017-05-20 17:12:36]
[2017-05-20 17:12:37]
[2017-05-20 17:12:38]
[2017-05-20 17:12:39]
main 10s after

这样,无论是定时任务,还是手动发送信号,只要在主程序中需要停止子线程的地方更改global_flag类中变量的状态,则负责控制子线程的线程就能获取到信号,停止子线程