Tornado的多進程管理分析

Tornado的HTTPServer是單進程單線程模式,同時提供了創建多進程服務器的接口,具體實現是在主進程啓動HTTPServer時通過process.fork_processes(num_processes)產生新的服務器子進程,所有進程之間共享端口。
Tornado的多進程管理我們可以參看process.py這個文件。

    global _task_id
    assert _task_id is None
    if num_processes is None or num_processes <= 0:
        num_processes = cpu_count()
    gen_log.info("Starting %d processes", num_processes)
    children = {}
    
def cpu_count() -> int:
    """Returns the number of processors on this machine."""
    if multiprocessing is None:
        return 1
    try:
        return multiprocessing.cpu_count()
    except NotImplementedError:
        pass
    try:
        return os.sysconf("SC_NPROCESSORS_CONF")  # type: ignore
    except (AttributeError, ValueError):
        pass
    gen_log.error("Could not detect number of processors; assuming 1")
    return 1

在沒有傳入進程數或者進程數<=0時,默認使用cpu個數作爲將要生成的進程個數。

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

這是一個內函數,作用就是生成子進程。它同時返回兩種狀態,os.fork()創建了子進程,如果子進程創建成功,返回子進程pid。子進程本身創建成功,返回自己的狀態碼,爲0.
如果pid==0表示cpu已經切換到子進程,else 則表示還在父進程中工作。

  for i in range(num_processes):
        id = start_child(i)
        if id is not None:
            return id

if id is not None表示如果我們在剛剛生成的那個子進程的上下文裏面,那麼就什麼都不幹,直接返回子進程的任務id就好了。如果還在父進程的上下文的話那麼就繼續生成子進程。

 num_restarts = 0
    while children:
        pid, status = os.wait()
        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

上面這段代碼都是在父進程進行的。pid, status = os.wait()的意思是等待任意子進程退出或者結束,這時候我們就把它從我們的children表裏面去除掉,然後通過status判斷子進程退出的原因。
果子進程是因爲接收到kill信號或者拋出exception了,那麼我們就重新啓動一個子進程,用的當然還是剛剛退出的那個子進程的任務號。如果子進程是自己把事情做完了才退出的,那麼就算了,等待別的子進程退出吧。

if new_id is not None:

    return new_id

主要就是退出子進程的空間,只在父進程上面做剩下的事情,不然剛纔父進程的那些代碼在子進程裏面也會同樣的運行,就會形成無限循環了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章