Introduction
Before Clubot use of the PYXMPP2 default Mainloop is a poll main loop, but the Clubot after the online resource occupancy is very severe, using strace tracking found Clubot in Non-stop poll, Viewing the PYXMPP2 code found that PYXMPP2 's poll uses a minimum timeout when using timeout blocking, and the minimum timeout is 0, so it becomes a non-blocking poll without timeouts, and does not intend to change the library code. So I wrote a more efficient Epoll Mainloop by imitating poll's mainloop.
Implement
#!/usr/bin/env python #-*-coding:utf-8-*-# author:cold # e-mail:wh_linux@126.com # date:13/01/06 10:41 : # Desc:clubot Epoll mainloop # __future__ Import absolute_import, Division import Select from Pyxmpp2.main Loop.interfaces import Handlerready, prepareagain from pyxmpp2.mainloop.base import mainloopbase from plugin.util Import
Get_logger class 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 () Main Loopbase.__init__ (self, settings, handlers) return def _add_io_handler (self, handler): Self._unprepared_handle Rs[hAndler] = None Self._configure_io_handler (handler) def _configure_io_handler (self, handler): If Self.check_even
TS (): 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 = handle R.fileno () If Old_fileno are 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[handle R] = Fileno if not fileno:return self._handlers[fileno] = Handler events = 0 if Handler.is_readab Le (): 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, Hand
Lerready): del Self._unprepared_handlers[handler] prepared = True elif isinstance (ret, Prepareagain): If Ret.timeout is not none:if self._timeout isn't none:self._timeout = min (self._timeout, Ret.timeo UT) 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 l Oop_iteration (Self, Timeout = m): 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_h Andler (handler) if self._timeout isn't none:timeout = min (timeout, self._timeout) if Next_timeout is not N one:timeout = min (next_timeout, timeout) if timeout = = 0:timeout = 1 # with a timeout of non-blocking, termination resources events = Sel F.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
Use
How do I use the new mainloop? Just pass in the instantiation of the client
Mainloop = Epollmainloop (settings)
client = Client (My_jid, [Self, version_provider], settings, Mainloop)
This will use Epoll as Mainloop
Attention
Epoll is only supported under Linux