Python 如果何避免程序僵尸

2015-06-16 14:15:54 +08:00
 sbmzhcn
import imaplib2, time
from threading import *

# This is the threading object that does all the waiting on 
# the event
class Idler(object):
    def __init__(self, conn):
        self.thread = Thread(target=self.idle)
        self.M = conn
        self.event = Event()

    def start(self):
        self.thread.start()

    def stop(self):
        # This is a neat trick to make thread end. Took me a 
        # while to figure that one out!
        print "evernt is set"
        self.event.set()

    def join(self):
        self.thread.join()

    def test(self):
        return self.thread.is_alive()

    def idle(self):
        # Starting an unending loop here
        while True:
            # This is part of the trick to make the loop stop 
            # when the stop() command is given
            if self.event.isSet():
                return
            self.needsync = False
            # A callback method that gets called when a new 
            # email arrives. Very basic, but that's good.
            def callback(args):
                if not self.event.isSet():
                    self.needsync = True
                    self.event.set()
            # Do the actual idle call. This returns immediately, 
            # since it's asynchronous.
            self.M.idle(callback=callback)
            # This waits until the event is set. The event is 
            # set by the callback, when the server 'answers' 
            # the idle call and the callback function gets 
            # called.
            self.event.wait()
            # Because the function sets the needsync variable,
            # this helps escape the loop without doing 
            # anything if the stop() is called. Kinda neat 
            # solution.
            if self.needsync:
                self.event.clear()
                self.dosync()

    # The method that gets called when a new email arrives. 
    # Replace it with something better.
    def dosync(self):
        print "Got an event!"

# Had to do this stuff in a try-finally, since some testing 
# went a little wrong.....
try:
    # Set the following two lines to your creds and server
    M = imaplib2.IMAP4_SSL("mail.example.com")
    M.login("mylogin","mypassword")
    # We need to get out of the AUTH state, so we just select 
    # the INBOX.
    M.select("INBOX")
    # Start the Idler thread
    idler = Idler(M)
    idler.start()
    # Because this is just an example, exit after 1 minute.
    time.sleep(1*60)
finally:
    # Clean up.
    idler.stop()
    idler.join()
    M.close()
    # This is important!
    M.logout()
class Notifier(Logger):
    def __init__(self, host, user, password, box='INBOX', debug=0, use_ssl=True):
        self.irc = None
        self.idler = None
        self.M = None
        self.messages = {}
        self.cybersquatting = {}
        while True:
            try:
                if use_ssl:
                    self.M = imaplib2.IMAP4_SSL(host, debug=debug)
                else:
                    self.M = imaplib2.IMAP4(host, debug=debug)
                self.M.login(user, password)
                self.M.select(box)
                self.idler = Idler(self.M, self)
                self.idler.start()
                while True:
                    # 这段代码一直执行,用来检查idler这个线程是否在活动
                    # 但有的时候代码在这儿会停止,不明白?
                    # 是不是idler thread还是is_alive?
                    if not self.idler.test():
                        raise ThreadDead()
                    try:
                        self.process_cybersquatting()
                    except:
                        pass
                    time.sleep(2)
            except imaplib2.IMAP4.abort:
                self.error("Disconnected.  Trying again!")
            except Exception as e:
                self.error("imaplib2 except:{}".format(e)
            time.sleep(2)

上面的代码Notifier有时会停止,找不到原因,现在觉得有几个可能

1.self.process_cybersquatting() 进入无限循环,这个不太可能,我查了好几遍,这个函数不可能无限循环的。另外这个不影响其它线程吧?
2.self.idler线程已经停止了,但self.idler.test()返回的还是True

每次都是到这一步def stop(self): 这个函数的时候再也不运行了。打印出evernt is set后,之后的代码再也没有任何响应了。

另外,有没有办法调试代码,让我知道到底程序卡到什么地方了,对于Python我还是初学者,请大家帮帮忙吧。

3044 次点击
所在节点    Python
9 条回复
binux
2015-06-16 14:28:42 +08:00
如果
self.event.wait()

if self.needsync:
之间,callback 和 self.stop() 同时执行了,你猜会发生什么
9hills
2015-06-16 14:34:12 +08:00
Debug 可以用pdb
sbmzhcn
2015-06-16 14:38:18 +08:00
@binux 能详细说说吗,同时执行了,`if not self.idler.test(): raise ThreadDead()` 这个会出现raise ThreadDead的吧,然后程序仍然可以重新运行啊。
sbmzhcn
2015-06-16 14:39:04 +08:00
@9hills 能帮我看看这代码有什么问题吗?
binux
2015-06-16 14:53:32 +08:00
@sbmzhcn 你说的不是
「每次都是到这一步def stop(self): 这个函数的时候再也不运行了。打印出evernt is set后,之后的代码再也没有任何响应了。」
吗?
lilydjwg
2015-06-16 14:54:46 +08:00
没看到你的 Notifier 在哪里用了。

你有两个地方设置 Event。如果它们同时执行到的话,你会把它清除掉但是不停止。不要把一个同步对象用作两种不同的目的。

PS: 你对 Thread 的使用很奇怪。
sbmzhcn
2015-06-16 16:02:09 +08:00
@lilydjwg 第一个代码是使用别人的示例。
lilydjwg
2015-06-16 17:19:03 +08:00
@sbmzhcn 那你的出问题的代码在哪里呢?Notifier 只是个类定义,不会被执行的呀。
sbmzhcn
2015-06-16 18:26:07 +08:00
问题我想我应该找到了,上面的人说的都不对应该。问题还是出在self.process_cybersquatting(), 由于socket产生了阻塞,导致一直等待状态。

具体的原因还没有证实,我等会用下异步socket,如果没问题,就是这个原因了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/198958

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX