亚欧色一区w666天堂,色情一区二区三区免费看,少妇特黄A片一区二区三区,亚洲人成网站999久久久综合,国产av熟女一区二区三区

  • 發布文章
  • 消息中心
點贊
收藏
評論
分享
原創

gunicorn的worker調度

2023-08-17 06:54:50
48
0

引言

前段時間分享了一篇如何提高django的并發能力的文章,由此引發了我對gunicorn的進一步研究,利用業余的時間看了一下gunicorn關于worker那部分的主要代碼,下邊以gevent為例子聊一聊它的工作流程(好吧目前主要看了看gevent這塊兒的代碼)。

歸納流程

  • gunicorn采用了n+1個進程,n就是真勞動worker數,即通過-w指定。1則是主worker,它負責管理這些勞動worker,它主要的工作就是對勞動worker進行增與殺,另外他會監聽一個端口,外提供服務。
  • 主worker在監聽端口會注冊一個文件描述符fd。
  • 勞動worker通過注冊的文件描述符不斷的接受請求。

部分細節分析

說明

如果對部分細節有興趣的話可以繼續看一下,當然默認你已經找到了gunicorn的代碼位置,一般在Python(安裝路徑)/lib/python3.x/site-packages/gunicorn

worker的創建

  • 啟動最先調用app/wsgiapp.py的run函數
  • 通過WSGIApplication(“%(prog)s [OPTIONS] [APP_MODULE]”).run()調用后邊的核心代碼
  • 根據執行的函數追蹤,最終會調用到arbiter.py的run函數,這才開始了漫長的創建過程,看一下核心代碼(篇幅原因,部分粘貼)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    def run(self):
    "Main master loop."
    # 這里啟動主進程,并監聽端口,注冊文件描述符
    self.start()
    util._setproctitle("master [%s]" % self.proc_name)
    try:
    # 這里負責啟動所有的從worker,也就是勞動worker
    self.manage_workers()
    while True:
    self.maybe_promote_master()
    sig = self.SIG_QUEUE.pop(0) if self.SIG_QUEUE else None
    if sig is None:
    self.sleep()
    # 則是kill掉那些unused/idle workers
    self.murder_workers()
    self.manage_workers()

    # 補充一下,所有的勞動worker,都放在self.WORKERS里,
    # 包含每個worker的pid等信息,主worker根據勞動者的運行時間等來決定是否將其殺死,
    # 可以看一下murder_workers函數的實現

勞動者與文件描述符綁定

  • 上邊提到的self.manage_workers()先會調用spawn_worker函數,部分代碼如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    worker.pid = os.getpid()
    try:
    util._setproctitle("worker [%s]" % self.proc_name)
    self.log.info("Booting worker with pid: %s", worker.pid)
    self.cfg.post_fork(self, worker)
    # 通過這里來調用你指定的worker的run函數,這里我指定的是gevent
    worker.init_process()
    sys.exit(0)
    except SystemExit:
    raise
    # 關于有哪幾種worker可以被調用,可以查看workers/__init__.py
  • ggevent.py的run函數

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # 為什么看ggevent,可以看一下works/__init__.py文件
    if self.server_class is not None:
    environ = base_environ(self.cfg)
    environ.update({
    "wsgi.multithread": True,
    "SERVER_SOFTWARE": VERSION,
    })
    server = self.server_class(
     s, application=self.wsgi, spawn=pool, log=self.log,
     handler_class=self.wsgi_handler, environ=environ,
    **ssl_args)
    else:
    # s其實就是監聽端口得到的那個socket
    hfun = partial(self.handle, s)
    # 這里就是綁定文件描述符的關鍵
     server = StreamServer(s, handle=hfun, spawn=pool, **ssl_args)

    server.start()
    servers.append(server)

    # StreamServer是gevent提供的一個類,繼承了BaseServer
    # 在BaseServer完成處理方法的綁定(If given, the request handler)

總結

雖然沒有看其他的工作方式流程,但大概應該差不多都是最前的三步過程,可能會有一些函數的不同,其實去看gunicorn的源碼無非就是想了解其工作流程,前邊的文章如何提高django的并發能力,遇到了當采用gevent方法啟動時會導致數據庫連接不能復用,后邊會繼續研究,希望能找到具體的原因。

0條評論
作者已關閉評論
yunson
9文章數
0粉絲數
yunson
9 文章 | 0 粉絲
原創

gunicorn的worker調度

2023-08-17 06:54:50
48
0

引言

前段時間分享了一篇如何提高django的并發能力的文章,由此引發了我對gunicorn的進一步研究,利用業余的時間看了一下gunicorn關于worker那部分的主要代碼,下邊以gevent為例子聊一聊它的工作流程(好吧目前主要看了看gevent這塊兒的代碼)。

歸納流程

  • gunicorn采用了n+1個進程,n就是真勞動worker數,即通過-w指定。1則是主worker,它負責管理這些勞動worker,它主要的工作就是對勞動worker進行增與殺,另外他會監聽一個端口,外提供服務。
  • 主worker在監聽端口會注冊一個文件描述符fd。
  • 勞動worker通過注冊的文件描述符不斷的接受請求。

部分細節分析

說明

如果對部分細節有興趣的話可以繼續看一下,當然默認你已經找到了gunicorn的代碼位置,一般在Python(安裝路徑)/lib/python3.x/site-packages/gunicorn

worker的創建

  • 啟動最先調用app/wsgiapp.py的run函數
  • 通過WSGIApplication(“%(prog)s [OPTIONS] [APP_MODULE]”).run()調用后邊的核心代碼
  • 根據執行的函數追蹤,最終會調用到arbiter.py的run函數,這才開始了漫長的創建過程,看一下核心代碼(篇幅原因,部分粘貼)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    def run(self):
    "Main master loop."
    # 這里啟動主進程,并監聽端口,注冊文件描述符
    self.start()
    util._setproctitle("master [%s]" % self.proc_name)
    try:
    # 這里負責啟動所有的從worker,也就是勞動worker
    self.manage_workers()
    while True:
    self.maybe_promote_master()
    sig = self.SIG_QUEUE.pop(0) if self.SIG_QUEUE else None
    if sig is None:
    self.sleep()
    # 則是kill掉那些unused/idle workers
    self.murder_workers()
    self.manage_workers()

    # 補充一下,所有的勞動worker,都放在self.WORKERS里,
    # 包含每個worker的pid等信息,主worker根據勞動者的運行時間等來決定是否將其殺死,
    # 可以看一下murder_workers函數的實現

勞動者與文件描述符綁定

  • 上邊提到的self.manage_workers()先會調用spawn_worker函數,部分代碼如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    worker.pid = os.getpid()
    try:
    util._setproctitle("worker [%s]" % self.proc_name)
    self.log.info("Booting worker with pid: %s", worker.pid)
    self.cfg.post_fork(self, worker)
    # 通過這里來調用你指定的worker的run函數,這里我指定的是gevent
    worker.init_process()
    sys.exit(0)
    except SystemExit:
    raise
    # 關于有哪幾種worker可以被調用,可以查看workers/__init__.py
  • ggevent.py的run函數

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # 為什么看ggevent,可以看一下works/__init__.py文件
    if self.server_class is not None:
    environ = base_environ(self.cfg)
    environ.update({
    "wsgi.multithread": True,
    "SERVER_SOFTWARE": VERSION,
    })
    server = self.server_class(
     s, application=self.wsgi, spawn=pool, log=self.log,
     handler_class=self.wsgi_handler, environ=environ,
    **ssl_args)
    else:
    # s其實就是監聽端口得到的那個socket
    hfun = partial(self.handle, s)
    # 這里就是綁定文件描述符的關鍵
     server = StreamServer(s, handle=hfun, spawn=pool, **ssl_args)

    server.start()
    servers.append(server)

    # StreamServer是gevent提供的一個類,繼承了BaseServer
    # 在BaseServer完成處理方法的綁定(If given, the request handler)

總結

雖然沒有看其他的工作方式流程,但大概應該差不多都是最前的三步過程,可能會有一些函數的不同,其實去看gunicorn的源碼無非就是想了解其工作流程,前邊的文章如何提高django的并發能力,遇到了當采用gevent方法啟動時會導致數據庫連接不能復用,后邊會繼續研究,希望能找到具體的原因。

文章來自個人專欄
文章 | 訂閱
0條評論
作者已關閉評論
作者已關閉評論
0
0