2019独角兽企业重金招聘Python工程师标准>>>

ngx_http_lua_run_posted_thread

这个函数主要是为了ngx.thread.spawn的处理,ngx.thread.spawn生成新的"light thread",这个"light thread"运行优先级比它的父协程高,会优先运行,父协程被迫暂停。"light thread"运行结束或者yield后,再由ngx_http_lua_run_posted_threads去运行父协程。

ngx.thread.spawn中创建"light thread"后, 调用ngx_http_lua_post_thread。

    if (ngx_http_lua_post_thread(r, ctx, ctx->cur_co_ctx) != NGX_OK) {return luaL_error(L, "no memory");}

ngx_http_lua_post_thread函数将父协程放在了ctx->posted_threads指向的链表中。

ngx_int_t
ngx_http_lua_post_thread(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx,ngx_http_lua_co_ctx_t *coctx)
{ngx_http_lua_posted_thread_t  **p;ngx_http_lua_posted_thread_t   *pt;pt = ngx_palloc(r->pool, sizeof(ngx_http_lua_posted_thread_t));if (pt == NULL) {return NGX_ERROR;}pt->co_ctx = coctx;pt->next = NULL;for (p = &ctx->posted_threads; *p; p = &(*p)->next) { /* void */ }*p = pt;return NGX_OK;
}

ngx_http_lua_run_posted_threads从ctx->posted_threads指向的链表中依次取出每个元素,调用ngx_http_lua_run_thread运行。

/* this is for callers other than the content handler */
ngx_int_t
ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L,ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
{ngx_int_t                        rc;ngx_http_lua_posted_thread_t    *pt;for ( ;; ) {if (c->destroyed) {return NGX_DONE;}pt = ctx->posted_threads;if (pt == NULL) {return NGX_DONE;}ctx->posted_threads = pt->next;ngx_http_lua_probe_run_posted_thread(r, pt->co_ctx->co,(int) pt->co_ctx->co_status);if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) {continue;}ctx->cur_co_ctx = pt->co_ctx;rc = ngx_http_lua_run_thread(L, r, ctx, 0);if (rc == NGX_AGAIN) {continue;}if (rc == NGX_DONE) {ngx_http_lua_finalize_request(r, NGX_DONE);continue;}/* rc == NGX_ERROR || rc >= NGX_OK */if (ctx->entered_content_phase) {ngx_http_lua_finalize_request(r, rc);}return rc;}/* impossible to reach here */
}

ngx_http_lua_run_thread使用方式

以lua-nginx-module的Access阶段的处理为例,实际的执行工作由ngx_http_lua_access_by_chunk函数中实现。 如下面的代码,调用ngx_http_lua_run_thread后根据返回值继续处理。

static ngx_int_t
ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r)
{/* 此处省去了创建协程的部分,只关注协程的运行  */rc = ngx_http_lua_run_thread(L, r, ctx, 0);dd("returned %d", (int) rc);if (rc == NGX_ERROR || rc > NGX_OK) {return rc;}c = r->connection;if (rc == NGX_AGAIN) {rc = ngx_http_lua_run_posted_threads(c, L, r, ctx);if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) {return rc;}if (rc != NGX_OK) {return NGX_DECLINED;}} else if (rc == NGX_DONE) {ngx_http_lua_finalize_request(r, NGX_DONE);rc = ngx_http_lua_run_posted_threads(c, L, r, ctx);if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) {return rc;}if (rc != NGX_OK) {return NGX_DECLINED;}}#if 1if (rc == NGX_OK) {if (r->header_sent) {dd("header already sent");/* response header was already generated in access_by_lua*,* so it is no longer safe to proceed to later phases* which may generate responses again */if (!ctx->eof) {dd("eof not yet sent");rc = ngx_http_lua_send_chain_link(r, ctx, NULL/* indicate last_buf */);if (rc == NGX_ERROR || rc > NGX_OK) {return rc;}}return NGX_HTTP_OK;}return NGX_OK;}
#endifreturn NGX_DECLINED;
}

ngx_http_lua_run_thread的返回值

函数ngx_http_lua_run_thread的返回值可分为下面几种

  • NGX_OK
  • NGX_AGAIN
  • NGX_DONE
  • NGX_ERROR: 执行出错
  • 大于200: 响应的HTTP状态码

按照Nginx的处理规则,返回NGX_ERROR或大于200的HTTP状态码时,将会无条件结束当前请求的处理。 返回NGX_OK表明当前阶段处理完成,此时只需要调用ngx_http_lua_send_chain_link发送响应即可。重点关注的是NGX_AGAIN和NGX_DONE这两个。返回这两个值时都要调用ngx_http_lua_run_posted_thread来处理。

NGX_AGAIN

ngx_http_lua_run_thread什么时候会返回NGX_AGAIN?

    1. ngx.sleep或ngx.socket等导致协程的yield
    1. 调用ngx.thread导致当前请求对应的一个父协程和一个或多个"light thread"没有全部退出。 由于情况2的存在,需要调用ngx_http_lua_run_posted_thread进行处理。

NGX_DONE

在Nginx中,NGX_DONE表示对当前请求的处理已经告一段落了,但是请求还没有处理完成,之后的工作会有其他的模块进行。主要出现在三个地方

  • 调用ngx_http_read_client_request_body读取请求包体时,由于从socket读取数据是异步的,会返回NGX_DONE。读取数据后对请求的处理由设置的回调函数执行
  • 调用ngx_http_internal_redirect执行了内部跳转
  • 创建子请求后,等待子请求完成后继续处理

在ngx_http_request_t中有一个作为引用计数的成员count。每次调用ngx_http_finalize_requet(r, NGX_DONE)时会将r的引用计数减一,减为0时才会真正结束当前请求。与此对应的模块返回NGX_DONE时都会有r->count++的操作。

在函数ngx_http_lua_access_by_chunk中当ngx_http_lua_run_thread返回NGX_DONE时(相比于返回值为NGX_AGAIN的情况)增加了一次ngx_http_finalize_request(r, NGX_DONE)的操作,就是为了将r的引用计数减一。

如果这里调用ngx_http_finalize_request(r, NGX_DONE)导致r的引用计数为0,将请求结束了,此时c->destory为true,再调用ngx_http_lua_run_posted_thread会直接返回。

转载于:https://my.oschina.net/u/2539854/blog/853894

ngx_lua中的协程调度(六)之ngx_http_lua_run_posted_thread相关推荐

  1. ngx_lua中的协程调度(三)

    2019独角兽企业重金招聘Python工程师标准>>> 通过lua-nginx-module的ngx.socket可以方便的建立与其他服务器的连接和数据传输,这些也是lua-rest ...

  2. 串行和并行的区别_入门参考:从Go中的协程理解串行和并行

    本文转自公众号语言随笔,欢迎关注 入门参考:从Go中的协程理解串行和并行​mp.weixin.qq.com Go语言的设计亮点之一就是原生实现了协程,并优化了协程的使用方式.使得用Go来处理高并发问题 ...

  3. 从根上理解高性能、高并发(五):深入操作系统,理解高并发中的协程

    本文原题"程序员应如何理解高并发中的协程",转载请联系作者. 1.系列文章引言 1.1 文章目的 作为即时通讯技术的开发者来说,高性能.高并发相关的技术概念早就了然与胸,什么线程池 ...

  4. Golang并发编程-GPM协程调度模型原理及组成分析

    文章目录 一.操作系统的进程和线程模型 1.1.基础知识 1.2.KST/ULT 二.Golang的GPM协程调度模型 三.M的结构及对应关系 四.P的结构及状态转换 五.G的结构及状态转换 六.GP ...

  5. golang异步协程调度原理

    golang异步协程调度 在1.14的go版本中,官方通过加入信号来进行协程的调度,后续就都支持了这种异步协程抢占,避免了早起的考栈调度时来检查是否执行超时的逻辑.本文简单来对比这种实现的原理. 调度 ...

  6. golang context 父子任务同步取消信号 协程调度 简介

    目录 前言 为什么需要context context是什么 context的使用 总结 前言 这篇文章将介绍Golang并发编程中常用到一种编程模式:context.本文将从为什么需要context出 ...

  7. python中多进程+协程的使用以及为什么要用它

    前面讲了为什么python里推荐用多进程而不是多线程,但是多进程也有其自己的限制:相比线程更加笨重.切换耗时更长,并且在python的多进程下,进程数量不推荐超过CPU核心数(一个进程只有一个GIL, ...

  8. 二十五、深入Python中的协程

    @Author: Runsen 一说并发,你肯定想到了多线程+进程模型,确实,多线程+进程,正是解决并发问题的经典模型之一.但对于多核CPU,利用多进程+协程的方式,能充分利用CPU,获得极高的性能. ...

  9. go 怎么等待所有的协程完成_Go 编程:如何实现协程调度的精准控制

    说起 Go 协程的调度,如果你了解 Go 调度器以及其实现的 G/P/M 模型,当然有助于应用的开发.但是在应用层面上,这些底层的调度原理并不会帮你太多,实现 Go 协程的精准调度得完全靠自己. 问题 ...

  10. Python中的协程

    Python中的协程 文章目录 Python中的协程 一.什么是协程 1.概念 2.协程的好处 3.缺点 二.了解协程的过程 1.yield工作原理 2.协程在运行过程中有四个状态: 3.预激协程的装 ...

最新文章

  1. vs2010设置boost开发环境
  2. 2018-2019-1 20165212 20165313 2016522 实验一 开发环境的熟悉
  3. vue .native 方法未定义_vue最新面试题
  4. python用户输入算式并计算_Python 70行代码实现简单算式计算器
  5. 水题 ZOJ 3875 Lunch Time
  6. [JAVA] IOException: Invalid byte 2 of 2-byte UTF-8 sequence(解决办法)
  7. 剑指offer:合并两个排序的链表
  8. functools学习有感
  9. Java从零开始(二) Tomacat
  10. MySQL的表数据复制
  11. android imageview 图片切换动画,在Android中以动画方式将ImageView移动到不同的位置...
  12. Fedora中systemctl命令的使用
  13. php 什么是函数式编程,函数式编程的介绍和归纳总结(附代码)
  14. 1.4 Linux文件系统与目录结构
  15. vpython_vpython初探
  16. 「TCG 规范解读」初识基础设施工作组
  17. 年轻设计师如何做好商业设计
  18. JS身份证号码校验,JS根据身份证号码获取出生年月日,JS根据出生年月日获取年龄,JS根据身份证号码获取性别
  19. R语言的Copula变量相关性分析
  20. 梯形法 微积分 c语言,关于 用辛普森法和梯形法求微积分的 程序!

热门文章

  1. (源码)群体智能优化算法之引力搜索算法(Gravitational Search Algorithm,GSA)
  2. 智能优化算法应用:基于GWO优化的指数熵图像多阈值分割 - 附代码
  3. 智能优化算法应用:基于GWO优化的对称交叉熵图像多阈值分割 - 附代码
  4. 从零基础入门Tensorflow2.0 ----四、15.tf.data读取csv文件并与tf.keras结合使用
  5. 模板题——图论相关(1)
  6. python 绘制多个子图
  7. 从python的random函数说起
  8. 珞珈一号影像辐射定标软件操作方法
  9. java zip 压缩文件夹_java zip 实现压缩文件和文件夹类Compressor.java
  10. 小红书如何实现高效推荐?解密背后的大数据计算平台架构