修改Python的pyxmpp2中的主迴圈使其提高效能

來源:互聯網
上載者:User
引子

之前clubot使用的pyxmpp2的預設mainloop也就是一個poll的主迴圈,但是clubot上線後資源佔用非常厲害,使用strace跟蹤發現clubot在不停的poll,查看pyxmpp2代碼發現pyxmpp2的poll在使用逾時阻塞時使用最小逾時時間,而最小逾時時間一直是0,所以會變成一個沒有逾時的非阻塞poll很浪費資源,不打算更改庫代碼,所以自己仿照poll的mainloop寫了一個更加高效的epoll的mainloop
實現

#!/usr/bin/env python# -*- coding:utf-8 -*-##  Author :  cold#  E-mail :  wh_linux@126.com#  Date  :  13/01/06 10:41:31#  Desc  :  Clubot epoll mainloop#from __future__ import absolute_import, divisionimport selectfrom pyxmpp2.mainloop.interfaces import HandlerReady, PrepareAgainfrom pyxmpp2.mainloop.base import MainLoopBasefrom plugin.util import get_loggerclass EpollMainLoop(MainLoopBase):  """ Main event loop based on the epoll() syscall on Linux system """  READ_ONLY = (select.EPOLLIN | select.EPOLLPRI | select.EPOLLHUP |         select.EPOLLERR |select.EPOLLET)  READ_WRITE = READ_ONLY | select.EPOLLOUT  def __init__(self, settings = None, handlers= None):    self.epoll = select.epoll()    self._handlers = {}    self._unprepared_handlers = {}    self._timeout = None    self._exists_fd = {}    self.logger = get_logger()    MainLoopBase.__init__(self, settings, handlers)    return  def _add_io_handler(self, handler):    self._unprepared_handlers[handler] = None    self._configure_io_handler(handler)  def _configure_io_handler(self, handler):    if self.check_events():      return    if handler in self._unprepared_handlers:      old_fileno = self._unprepared_handlers[handler]      prepared = self._prepare_io_handler(handler)    else:      old_fileno = None      prepared = True    fileno = handler.fileno()    if old_fileno is not None and fileno != old_fileno:      del self._handlers[old_fileno]      self._exists.pop(old_fileno, None)      self.epoll.unregister(old_fileno)    if not prepared:      self._unprepared_handlers[handler] = fileno    if not fileno:      return    self._handlers[fileno] = handler    events = 0    if handler.is_readable():      events |= self.READ_ONLY    if handler.is_writable():      events |= self.READ_WRITE    if events:      if fileno in self._exists_fd:        self.epoll.modify(fileno, events)      else:        self._exists_fd.update({fileno:1})        self.epoll.register(fileno, events)  def _prepare_io_handler(self, handler):    ret = handler.prepare()    if isinstance(ret, HandlerReady):      del self._unprepared_handlers[handler]      prepared = True    elif isinstance(ret, PrepareAgain):      if ret.timeout is not None:        if self._timeout is not None:          self._timeout = min(self._timeout, ret.timeout)        else:          self._timeout = ret.timeout      prepared = False    else:      raise TypeError("Unexpected result from prepare()")    return prepared  def _remove_io_handler(self, handler):    if handler in self._unprepared_handlers:      old_fileno = self._unprepared_handlers[handler]      del self._unprepared_handlers[handler]    else:      old_fileno = handler.fileno()    if old_fileno is not None:      try:        del self._handlers[old_fileno]        self._exists.pop(old_fileno, None)        self.epoll.unregister(old_fileno)      except KeyError:        pass  def loop_iteration(self, timeout = 60):    next_timeout, sources_handled = self._call_timeout_handlers()    if self.check_events():      return    if self._quit:      return sources_handled    for handler in list(self._unprepared_handlers):      self._configure_io_handler(handler)    if self._timeout is not None:      timeout = min(timeout, self._timeout)    if next_timeout is not None:      timeout = min(next_timeout, timeout)    if timeout == 0:      timeout += 1  # 帶有逾時的非阻塞,解約資源    events = self.epoll.poll(timeout)    for fd, flag in events:      if flag & (select.EPOLLIN | select.EPOLLPRI | select.EPOLLET):        self._handlers[fd].handle_read()      if flag & (select.EPOLLOUT|select.EPOLLET):        self._handlers[fd].handle_write()      if flag & (select.EPOLLERR | select.EPOLLET):        self._handlers[fd].handle_err()      if flag & (select.EPOLLHUP | select.EPOLLET):        self._handlers[fd].handle_hup()      #if flag & select.EPOLLNVAL:        #self._handlers[fd].handle_nval()      sources_handled += 1      self._configure_io_handler(self._handlers[fd])    return sources_handled

使用

如何使用新的mainloop?只需在執行個體化Client時傳入

mainloop = EpollMainLoop(settings)client = Client(my_jid, [self, version_provider], settings, mainloop)

這樣就會使用epoll作為mainloop
注意

epoll僅僅在Linux下支援

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.