亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 網站 > Nginx > 正文

nginx源碼分析線程池詳解

2024-08-30 12:28:56
字體:
來源:轉載
供稿:網友

nginx源碼分析線程池詳解

一、前言

     nginx是采用多進程模型,master和worker之間主要通過pipe管道的方式進行通信,多進程的優勢就在于各個進程互不影響。但是經常會有人問道,nginx為什么不采用多線程模型(這個除了之前一篇文章講到的情況,別的只有去問作者了,HAHA)。其實,nginx代碼中提供了一個thread_pool(線程池)的核心模塊來處理多任務的。下面就本人對該thread_pool這個模塊的理解來跟大家做些分享(文中錯誤、不足還請大家指出,謝謝) 

二、thread_pool線程池模塊介紹

     nginx的主要功能都是由一個個模塊構成的,thread_pool也不例外。線程池主要用于讀取、發送文件等IO操作,避免慢速IO影響worker的正常運行。先引用一段官方的配置示例

Syntax: thread_pool name threads=number [max_queue=number];Default: thread_pool default threads=32 max_queue=65536;Context: main

     根據上述的配置說明,thread_pool是有名字的,上面的線程數目以及隊列大小都是指每個worker進程中的線程,而不是所有worker中線程的總數。一個線程池中所有的線程共享一個隊列,隊列中的最大人數數量為上面定義的max_queue,如果隊列滿了的話,再往隊列中添加任務就會報錯。 

     根據之前講到過的模塊初始化流程(在master啟動worker之前) create_conf--> command_set函數-->init_conf,下面就按照這個流程看看thread_pool模塊的初始化

/******************* nginx/src/core/ngx_thread_pool.c ************************///創建線程池所需的基礎結構static void * ngx_thread_pool_create_conf(ngx_cycle_t *cycle){  ngx_thread_pool_conf_t *tcf;   //從cycle->pool指向的內存池中申請一塊內存  tcf = ngx_pcalloc(cycle->pool, sizeof(ngx_thread_pool_conf_t));  if (tcf == NULL) {    return NULL;  }      //先申請包含4個ngx_thread_pool_t指針類型元素的數組   //ngx_thread_pool_t結構體中保存了一個線程池相關的信息  if (ngx_array_init(&tcf->pools, cycle->pool, 4,            sizeof(ngx_thread_pool_t *))    != NGX_OK)  {    return NULL;  }   return tcf;} //解析處理配置文件中thread_pool的配置,并將相關信息保存的ngx_thread_pool_t中static char * ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){  ngx_str_t     *value;  ngx_uint_t     i;  ngx_thread_pool_t *tp;   value = cf->args->elts;   //根據thread_pool配置中的name作為線程池的唯一標識(如果重名,只有第一個有效)  //申請ngx_thread_pool_t結構保存線程池的相關信息  //由此可見,nginx支持配置多個name不同的線程池  tp = ngx_thread_pool_add(cf, &value[1]);  .......  //處理thread_pool配置行的所有元素  for (i = 2; i < cf->args->nelts; i++) {    //檢查配置的線程數    if (ngx_strncmp(value[i].data, "threads=", 8) == 0) {     .......    }         //檢查配置的最大隊列長度    if (ngx_strncmp(value[i].data, "max_queue=", 10) == 0) {     .......    }  }  ......} //判斷包含多個線程池的數組中的各個線程池的配置是否正確static char * ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf){  ....  ngx_thread_pool_t **tpp;   tpp = tcf->pools.elts;  //遍歷數組中所有的線程池配置,并檢查其正確性  for (i = 0; i < tcf->pools.nelts; i++) {    .....  }   return NGX_CONF_OK;}

     在上述的流程走完之后,nginx的master就保存了一份所有線程池的配置(tcf->pools),這份配置在創建worker時也會被繼承。然后每個worker中都調用各個核心模塊的init_process函數(如果有的話)。

/******************* nginx/src/core/ngx_thread_pool.c ************************///創建線程池所需的基礎結構static ngx_int_tngx_thread_pool_init_worker(ngx_cycle_t *cycle){  ngx_uint_t        i;  ngx_thread_pool_t    **tpp;  ngx_thread_pool_conf_t  *tcf;  //如果不是worker或者只有一個worker就不起用線程池  if (ngx_process != NGX_PROCESS_WORKER    && ngx_process != NGX_PROCESS_SINGLE)  {    return NGX_OK;  }     //初始化任務隊列  ngx_thread_pool_queue_init(&ngx_thread_pool_done);   tpp = tcf->pools.elts;  for (i = 0; i < tcf->pools.nelts; i++) {    //初始化各個線程池    if (ngx_thread_pool_init(tpp[i], cycle->log, cycle->pool) != NGX_OK) {      return NGX_ERROR;    }  }   return NGX_OK;} //線程池初始化static ngx_int_t ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, ngx_pool_t *pool){  .....  //初始化任務隊列  ngx_thread_pool_queue_init(&tp->queue);   //創建線程鎖  if (ngx_thread_mutex_create(&tp->mtx, log) != NGX_OK) {    return NGX_ERROR;  }   //創建線程條件變量  if (ngx_thread_cond_create(&tp->cond, log) != NGX_OK) {    (void) ngx_thread_mutex_destroy(&tp->mtx, log);    return NGX_ERROR;  }  ......  for (n = 0; n < tp->threads; n++) {    //創建線程池中的每個線程    err = pthread_create(&tid, &attr, ngx_thread_pool_cycle, tp);    if (err) {      ngx_log_error(NGX_LOG_ALERT, log, err,             "pthread_create() failed");      return NGX_ERROR;    }  }  ......} //線程池中線程處理主函數static void *ngx_thread_pool_cycle(void *data){   ......   for ( ;; ) {    //阻塞的方式獲取線程鎖    if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {      return NULL;    }     /* the number may become negative */    tp->waiting--;     //如果任務隊列為空,就cond_wait阻塞等待有新任務時調用cond_signal/broadcast觸發    while (tp->queue.first == NULL) {      if (ngx_thread_cond_wait(&tp->cond, &tp->mtx, tp->log)        != NGX_OK)      {        (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);        return NULL;      }    }    //從任務隊列中獲取task,并將其從隊列中移除    task = tp->queue.first;    tp->queue.first = task->next;     if (tp->queue.first == NULL) {      tp->queue.last = &tp->queue.first;    }     if (ngx_thread_mutex_unlock(&tp->mtx, tp->log) != NGX_OK) {      return NULL;    }    ......    //task的處理函數    task->handler(task->ctx, tp->log);    .....     ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);     //將經過預處理的任務添加到done隊列中等待調用event的回調函數繼續處理    *ngx_thread_pool_done.last = task;    ngx_thread_pool_done.last = &task->next;         //防止編譯器優化,保證解鎖操作是在上述語句執行完畢后再去執行的    ngx_memory_barrier();     ngx_unlock(&ngx_thread_pool_done_lock);         (void) ngx_notify(ngx_thread_pool_handler);  }} //處理pool_done隊列上task中包含的每個event事件static void ngx_thread_pool_handler(ngx_event_t *ev){  .....  ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);   //獲取任務鏈表的頭部  task = ngx_thread_pool_done.first;  ngx_thread_pool_done.first = NULL;  ngx_thread_pool_done.last = &ngx_thread_pool_done.first;   ngx_memory_barrier();   ngx_unlock(&ngx_thread_pool_done_lock);   while (task) {    ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,            "run completion handler for task #%ui", task->id);    //遍歷隊列中的所有任務事件    event = &task->event;    task = task->next;     event->complete = 1;    event->active = 0;     //調用event對應的處理函數有針對性的進行處理    event->handler(event);  }} 

三、thread_pool線程池使用示例

     根據之前所講到的,nginx中的線程池主要是用于操作文件的IO操作。所以,在nginx中自帶的模塊ngx_http_file_cache.c文件中看到了線程池的使用。

/*********************** nginx/src/os/unix/ngx_files.c **********************///file_cache模塊的處理函數(涉及到了線程池)static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c){  .......#if (NGX_THREADS)   if (clcf->aio == NGX_HTTP_AIO_THREADS) {    c->file.thread_task = c->thread_task;    //這里注冊的函數在下面語句中的ngx_thread_read函數中被調用    c->file.thread_handler = ngx_http_cache_thread_handler;    c->file.thread_ctx = r;    //根據任務的屬性,選擇正確的線程池,并初始化task結構體中的各個成員        n = ngx_thread_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);     c->thread_task = c->file.thread_task;    c->reading = (n == NGX_AGAIN);     return n;  }#endif   return ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);}  //task任務的處理函數static ngx_int_t ngx_http_cache_thread_handler(ngx_thread_task_t *task, ngx_file_t *file){  .......  tp = clcf->thread_pool;  .......     task->event.data = r;  //注冊thread_event_handler函數,該函數在處理pool_done隊列中event事件時被調用  task->event.handler = ngx_http_cache_thread_event_handler;   //將任務放到線程池的任務隊列中  if (ngx_thread_task_post(tp, task) != NGX_OK) {    return NGX_ERROR;  }  ......} /*********************** nginx/src/core/ngx_thread_pool.c **********************///添加任務到隊列中ngx_int_t ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task){  //如果當前的任務正在處理就退出  if (task->event.active) {    ngx_log_error(NGX_LOG_ALERT, tp->log, 0,           "task #%ui already active", task->id);    return NGX_ERROR;  }   if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {    return NGX_ERROR;  }     //判斷當前線程池等待的任務數量與最大隊列長度的關系  if (tp->waiting >= tp->max_queue) {    (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);     ngx_log_error(NGX_LOG_ERR, tp->log, 0,           "thread pool /"%V/" queue overflow: %i tasks waiting",           &tp->name, tp->waiting);    return NGX_ERROR;  }  //激活任務  task->event.active = 1;   task->id = ngx_thread_pool_task_id++;  task->next = NULL;     //通知阻塞的線程有新事件加入,可以解除阻塞  if (ngx_thread_cond_signal(&tp->cond, tp->log) != NGX_OK) {    (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);    return NGX_ERROR;  }   *tp->queue.last = task;  tp->queue.last = &task->next;   tp->waiting++;   (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);   ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,          "task #%ui added to thread pool /"%V/"",          task->id, &tp->name);   return NGX_OK;}

    上面示例基本展示了nginx目前對線程池的使用方法,采用線程池來處理IO這類慢速操作可以提升worker的主線程的執行效率。當然,用戶自己在開發模塊時,也可以參照file_cache模塊中使用線程池的方法來調用多線程提升程序性能。(歡迎大家多多批評指正)

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美在线一级va免费观看| 国产精品一区=区| 国产欧美亚洲视频| 日韩av网站导航| 欧美成人激情视频| 亚洲福利在线看| 欧美日韩亚洲国产一区| 欧美日韩免费在线| 亚洲色图激情小说| 亚洲国产精品字幕| 国产精品久久91| 欧美成人sm免费视频| 久久久极品av| 国产精品99久久久久久久久| 91性高湖久久久久久久久_久久99| 日韩欧美国产免费播放| 亚洲第五色综合网| 亚洲欧洲自拍偷拍| 97色在线观看免费视频| 亚洲美女av网站| 欧洲永久精品大片ww免费漫画| 国产精品久久久久久久久久小说| 一区二区三区精品99久久| 欧美三级xxx| 亚洲午夜av久久乱码| 国产精品色悠悠| 欧美巨猛xxxx猛交黑人97人| 一区二区三区回区在观看免费视频| 91社影院在线观看| 日韩欧美国产成人| 国产精品视频免费观看www| 97精品视频在线观看| 欧美成人剧情片在线观看| 国模精品一区二区三区色天香| 欧美精品第一页在线播放| 国产热re99久久6国产精品| 午夜精品久久久久久久99黑人| 国产精品高潮在线| 欧美中文字幕在线观看| 色偷偷av亚洲男人的天堂| 欧美国产日本在线| 精品久久中文字幕久久av| 国产精品一久久香蕉国产线看观看| 亚洲精品动漫100p| 2024亚洲男人天堂| 亚洲精品电影在线| 亚洲色无码播放| 欧美成人午夜激情| 欧美在线免费视频| 国产成人精品亚洲精品| 91九色蝌蚪国产| 国产精品人成电影| 亚洲欧洲午夜一线一品| 亚洲精品国产免费| 秋霞午夜一区二区| 欧美激情在线有限公司| yellow中文字幕久久| 国产精品扒开腿爽爽爽视频| 亚洲精品久久久久久久久| 亚洲成人国产精品| 91精品中文在线| 亚洲韩国日本中文字幕| 欧美区在线播放| 国产成人精品久久亚洲高清不卡| 国产网站欧美日韩免费精品在线观看| 欧美激情视频在线观看| 91超碰caoporn97人人| 亚洲国产日韩精品在线| 国产亚洲视频在线观看| 精品久久久久久久久久国产| 亚洲欧美国产视频| 国产精品一区=区| 色综合天天狠天天透天天伊人| 国产午夜精品美女视频明星a级| 国外成人免费在线播放| 精品国产自在精品国产浪潮| 91国内产香蕉| 国产亚洲日本欧美韩国| 亚洲国产日韩欧美在线动漫| 性欧美亚洲xxxx乳在线观看| 国外成人在线播放| 中文字幕日本精品| 九色精品免费永久在线| 91老司机精品视频| 亚洲视频专区在线| 精品福利樱桃av导航| 日韩精品免费在线视频| 国产成人精品av在线| 亚洲欧美日韩图片| 亚洲精品国偷自产在线99热| 中文字幕日韩精品在线| 欧美亚洲第一区| 国产性色av一区二区| 国产日韩在线视频| 欧美诱惑福利视频| 亚洲精品99久久久久中文字幕| 成人av.网址在线网站| 97久久伊人激情网| 国产精品一区二区久久久| 97热在线精品视频在线观看| 美日韩丰满少妇在线观看| 海角国产乱辈乱精品视频| 久久夜色精品国产亚洲aⅴ| 亚洲国产精品电影| 欧美亚洲午夜视频在线观看| 不卡av在线播放| www.久久撸.com| 欧美日韩国产丝袜另类| 亚洲aⅴ男人的天堂在线观看| www.日韩不卡电影av| 精品国产精品三级精品av网址| 亚洲第一页中文字幕| 国产精品2018| 最近2019好看的中文字幕免费| 久久精彩免费视频| 91亚洲精品视频| 亲子乱一区二区三区电影| 91国产一区在线| 精品国偷自产在线视频99| 2019中文字幕免费视频| 欧美亚洲另类激情另类| 国产婷婷成人久久av免费高清| www.亚洲一二| 欧美福利小视频| 久久成人一区二区| 色偷偷噜噜噜亚洲男人的天堂| 欧美怡春院一区二区三区| 国产suv精品一区二区三区88区| 久久久噜噜噜久久久| 欧美综合激情网| 欧美老女人bb| www.欧美视频| 国产亚洲成av人片在线观看桃| 国产精品视频最多的网站| 亚洲精品免费一区二区三区| www.欧美精品| 亚洲精品二三区| www欧美xxxx| 国产福利精品av综合导导航| 中文字幕日韩欧美在线| 国产亚洲精品高潮| 亚洲午夜av久久乱码| 日韩亚洲国产中文字幕| 成人a视频在线观看| 亚洲美女av在线播放| 蜜月aⅴ免费一区二区三区| 国产噜噜噜噜噜久久久久久久久| 国产精品18久久久久久麻辣| 福利二区91精品bt7086| 久久九九亚洲综合| 中文字幕亚洲欧美日韩高清| 性亚洲最疯狂xxxx高清| 久久激情视频久久| 亚洲综合一区二区不卡| 中文字幕欧美亚洲| 成人黄色影片在线| 亚洲自拍高清视频网站| 亚洲国产精品成人精品| 日韩欧美国产骚| 亚洲jizzjizz日本少妇| xvideos亚洲人网站| 久久99精品久久久久久青青91| 国产99视频精品免视看7| 欧美性xxxx极品高清hd直播|