当前位置:网站首页>Tornado multi process service

Tornado multi process service

2022-07-26 09:14:00 Or turn around

tornado Multi process start

In the foreword "tornado And hello world" I have briefly introduced tornado Basic use of .tornado By default, a single process is started , The starting mode is as follows :

if __name__ == "__main__":
    application = tornado.web.Application([(r"/", MainHandler)])
    # application.listen(8888)
    server = HTTPServer(application)
    server.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

If you want to start multiple processes , The following modifications can be made :

if __name__ == "__main__":
    application = tornado.web.Application([(r"/", MainHandler)])
    server = HTTPServer(application)
    server.bind(8888)
    server.start(2)
    tornado.ioloop.IOLoop.instance().start()

Generated after startup 3 A process ( Watch out for closure. debug Pattern ).start The parameters in the function are described as follows :

If num_processes is ``None`` or <= 0, we detect the number of cores
available on this machine and fork that number of child
processes. If num_processes is given and > 1, we fork that
specific number of sub-processes.

intend , When the parameter is less than or equal to 0 when , According to the current machine cpu Number of cores to create sub processes , Greater than 1 Directly create a child process according to the specified parameters .
to glance at bind Function description :

def bind(self, port, address=None, family=socket.AF_UNSPEC, backlog=128,
         reuse_port=False):
    """Binds this server to the given port on the given address.

    To start the server, call `start`. If you want to run this server
    in a single process, you can call `listen` as a shortcut to the
    sequence of `bind` and `start` calls.

    Address may be either an IP address or hostname.  If it's a hostname,
    the server will listen on all IP addresses associated with the
    name.  Address may be an empty string or None to listen on all
    available interfaces.  Family may be set to either `socket.AF_INET`
    or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
    both will be used if available.

    The ``backlog`` argument has the same meaning as for
    `socket.listen <socket.socket.listen>`. The ``reuse_port`` argument
    has the same meaning as for `.bind_sockets`.

    This method may be called multiple times prior to `start` to listen
    on multiple ports or interfaces.

    .. versionchanged:: 4.4
       Added the ``reuse_port`` argument.
    """

in other words , When start The argument to the function is 1 when ,listen Function can replace bind and start.

Multi process startup principle

Analyze the startup code :
So let's create one HTTPServer example . And then in bind Function , Called bind_sockets Method to create sockets. And then start In the method , call process.fork_processes(num_processes) Method to create a child process , And will sockets adopt add_sockets Method to add to server In the example .
in other words , The essence of this code is as follows :

if __name__ == "__main__":
    application = tornado.web.Application([(r"/", MainHandler)])
    sockets = tornado.netutil.bind_sockets(8888)
    tornado.process.fork_processes(2)
    server = HTTPServer(application)
    server.add_sockets(sockets)
    tornado.ioloop.IOLoop.instance().start()

Continue analysis fork_process function , The main process is as follows :

def start_child(i):
    pid = os.fork()
    if pid == 0:
        # child process
        _reseed_random()
        global _task_id
        _task_id = i
        return i
    else:
        children[pid] = i
        return None

for i in range(num_processes):
    id = start_child(i)
    if id is not None:
        return id
num_restarts = 0
while children:
    try:
        pid, status = os.wait()
    except OSError as e:
        if errno_from_exception(e) == errno.EINTR:
            continue
        raise
    if pid not in children:
        continue
    id = children.pop(pid)
    if os.WIFSIGNALED(status):
        gen_log.warning("child %d (pid %d) killed by signal %d, restarting",
                        id, pid, os.WTERMSIG(status))
    elif os.WEXITSTATUS(status) != 0:
        gen_log.warning("child %d (pid %d) exited with status %d, restarting",
                        id, pid, os.WEXITSTATUS(status))
    else:
        gen_log.info("child %d (pid %d) exited normally", id, pid)
        continue
    num_restarts += 1
    if num_restarts > max_restarts:
        raise RuntimeError("Too many child restarts, giving up")
    new_id = start_child(id)
    if new_id is not None:
        return new_id
# All child processes exited cleanly, so exit the master process
# instead of just returning to right after the call to
# fork_processes (which will probably just start up another IOLoop
# unless the caller checks the return value).
sys.exit(0)

From this source code, we can see , The start of the subprocess is actually called linux The system provides fork function . When a child process exists , The parent process passes through a while Loop to process the termination signal of the child process , Try to restart the child process that has been stopped , Until the default maximum number of restarts is exceeded 100.

原网站

版权声明
本文为[Or turn around]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/207/202207260855497445.html