V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
sbmzhcn
V2EX  ›  Python

Python 如果何避免程序僵尸

  •  
  •   sbmzhcn · 2015-06-16 14:15:54 +08:00 · 3121 次点击
    这是一个创建于 3454 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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我还是初学者,请大家帮帮忙吧。

    9 条回复    2015-06-16 18:26:07 +08:00
    binux
        1
    binux  
       2015-06-16 14:28:42 +08:00
    如果
    self.event.wait()

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

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

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

    具体的原因还没有证实,我等会用下异步socket,如果没问题,就是这个原因了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4022 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 10:15 · PVG 18:15 · LAX 02:15 · JFK 05:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.