d2js 运行于 servlet 容器,如tomcat,由于容器自身支持并发,似乎 d2js 只要使用 nashorn 运行脚本即可。这样我们得到最简单的实现方式:

在该方式中,nashorn引擎仅存在于Servlet.service调用栈,在调用完成后即释放。Hotspot 将栈上对象(局部变量、牵连的函数调用中的局部变量)也分配在堆里,但是栈上对象存活时间很短,只要新生代空间足够,其永远不会进入年老代,回收策略简单。对于高并发少持久数据的网站系统,加大新生代当是有效做法。

为每个请求创建ScriptEngine的方式缺陷明显:

1.每次都创建一个 ScriptEngine,输出响应后即释放,代价很高

2.每次脚本都要编译(nashorn 确实编译了js),花销很大

以上缺陷导致该方式没有实用价值,仅在开发原型时有意义。但该方式也有它的参考意义:隔离是并发的秘诀,充分的隔离=完美的并发,该方式对每个请求使用独立的ScriptEngine,开发者在 js 中可以尽情使用全局变量而不用担心全局污染,这也使人员要求大为降低。

本轮优化前 d2js 使用的是这个方案的升级版本,采用“每个 d2js 文件一个 ScriptEngine Pool” 的方案,可以方便的使用全局变量,对开发人员要求较低。这个办法资源消耗巨大,行不通。

性能优化的目标是:让所有d2js文件运行于同一引擎实例!!每个d2js文件只加载一次,除非文件发生写入。

同一引擎不存在难度,就是个单例。但总有一些弯路让我们技痒难耐。比如有一个貌似合理的替代方案:ThreadLocal<ScriptEngine>,这个方案假设 ScriptEngine 只适合单线程,考虑到目前 jdbc 都是同步的,在 d2js函数调用期间,不会发生线程切换,采用 ThreadLocal 即使使用全局变量也是安全的——既然引擎是线程安全的,引擎内的变量自然也是线程安全的。但该方式实测性能不及使用同一引擎。

使用同一引擎后,原来通过全局变量表示的 d2js, request, response,session 等都需要重构。

首先是 d2js 对象。d2js 文件中接口是以 d2js.func = function(){} 形式插拔的。使用同一引擎后,d2js 不再是全局变量,要保持该表达方式,目前采用的办法是对每个d2js文件套用一个模板代码,该模板是一个外层闭包,将 d2js 化为该闭包的变量:

function createD2js(){

    var d2js/**/ = new D2JS();

    // ------- 用户代码插入模板-----------------
d2js.func = function(){}   // 将用户代码置入模板内
// --------以上用户代码--------------------- … … return d2js; } 

加载 d2js 文件时套用模板、执行该模板函数并获得返回值。每个 d2js 文件都得到一个 D2JS 实例,所有D2JS实例存放于 ConcurrentHashMap<String filename, Object D2JS Instance> allD2js 。

处理HTTP请求时,根据文件名找到 D2JS 实例,由相应实例提供服务。

d2js 函数中还需要访问 request, response, session 等对象。这些对象是HTTP请求带来的,每个请求都不同,同一 d2js 对象要支持对并发请求提供服务。由于使用的是同一个ScriptEngine,全局变量表达方式显然行不通了。可行的有两种做法:

1. 扩充参数栈,增加一个参数:d2js.func = function(params, http){}

http 是封装了 {request:request, response: response, session: session} 的一个对象,一个复合粒子。

这个方式的好处是,有时 d2js.func 不需要使用 request 等对象,该形参就可以留空,重构代价不大。缺点是,当函数需要更多参数时(如给其它函数调用的私有函数),很难确切知道应该在哪个位置提供该参数。

2.将 request, response 等表达为 this.request, this.response。这个做法更有效,最终选择了这种方式。

怎么才能让同一个 d2js 实例分别对应不同的 request、response 呢?

办法很有趣。我将上述存放在 allD2js 中的 D2JS 实例作为 prototype,每次请求时创建一个基于该 prototype 的新实例为该请求服务,服务完毕后该实例即释放。

该方式流程如下:

在原理上这种一次性的附带上当次调用信息的镜像实例与闭包的偏函数(柯里化)本质相同。该实现方式发挥了 js 语言原型链思想,特别适合按上下文偏分服务的并发情形,和 erlang 将偏分信息全部放置于栈相比,该方式具备基于原型链的面向对象特点,但又延续了栈隔离的特色。未来 nashorn 实现 async/await、 jdbc 实现 async-jdbc 后,该并发表达方式将会获得更强的生命力。

采取该方式后,每次请求仅在栈上生成一个镜像 D2JS 对象,内存消耗少,业务间互相隔绝,除修改D2JS文件导致的并发冲突外,无其它潜在冲突资源,不使用任何锁。实测效率与 JSP 相比约为 JSP 的 50%-90%,对于运行于 JVM 的脚本语言这已经非常不错了。

D2js 是如何处理并发的的更多相关文章

  1. iis如何处理并发请求

    文章:IIS是怎么处理同时到来的多个请求的? 文章:你真的了解:IIS连接数.IIS并发连接数.IIS最大并发工作线程数.应用程序池的队列长度.应用程序池的... 文章:IIS最大工作进程数设置引发串 ...

  2. flask如何处理并发

    1.使用自身服务器的多进程或者多线程,参考werkzeug的run_simple函数的入参.注意,进程和线程不能同时开启 2.使用gunicorn使用多进程,-w worker 进程数,类型于运行多个 ...

  3. Code First开发系列之管理并发和事务

    返回<8天掌握EF的Code First开发>总目录 本篇目录 理解并发 理解积极并发 理解消极并发 使用EF实现积极并发 EF的默认并发 设计处理字段级别的并发应用 实现RowVersi ...

  4. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序处理并发

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第十篇:为ASP.NET MVC应用程序 ...

  5. Code First开发系列之管理并发和事务(转)

    转自:http://www.cnblogs.com/farb/p/ConcurrencyAndTransctionManagement.html 返回<8天掌握EF的Code First开发&g ...

  6. EntityFramework_MVC4中EF5 新手入门教程之七 ---7.通过 Entity Framework 处理并发

    在以前的两个教程你对关联数据进行了操作.本教程展示如何处理并发性.您将创建工作与各Department实体的 web 页和页,编辑和删除Department实体将处理并发错误.下面的插图显示索引和删除 ...

  7. linux设备驱动第五篇:驱动中的并发与竟态

    综述 在上一篇介绍了linux驱动的调试方法,这一篇介绍一下在驱动编程中会遇到的并发和竟态以及如何处理并发和竞争. 首先什么是并发与竟态呢?并发(concurrency)指的是多个执行单元同时.并行被 ...

  8. Contoso 大学 - 7 – 处理并发

    原文 Contoso 大学 - 7 – 处理并发 By Tom Dykstra, Tom Dykstra is a Senior Programming Writer on Microsoft's W ...

  9. [翻译][MVC 5 + EF 6] 10:处理并发

    原文:Handling Concurrency with the Entity Framework 6 in an ASP.NET MVC 5 Application 1.并发冲突: 当一个用户编辑一 ...

随机推荐

  1. (转)Java中的static关键字解析

    转载: http://www.cnblogs.com/dolphin0520/p/3799052.html 一.static关键字的用途 在<Java编程思想>P86页有这样一段话: &q ...

  2. Nginx深入详解之多进程网络模型

    一.进程模型        Nginx之所以为广大码农喜爱,除了其高性能外,还有其优雅的系统架构.与Memcached的经典多线程模型相比,Nginx是经典的多进程模型.Nginx启动后以daemon ...

  3. [LeetCode] Repeated Substring Pattern 重复子字符串模式

    Given a non-empty string check if it can be constructed by taking a substring of it and appending mu ...

  4. [LeetCode] Merge k Sorted Lists 合并k个有序链表

    Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 这 ...

  5. .NET跨平台之旅:将示例站点从 ASP.NET 5 RC1 升级至 ASP.NET Core 1.0

    终于将“.NET跨平台之旅”的示例站点 about.cnblogs.com 从 ASP.NET 5 RC1 升级至 ASP.NET Core 1.0 ,经历了不少周折,在这篇博文中记录一下. 从 AS ...

  6. C# readonly 与const

    引自:http://www.cnblogs.com/ryuasuka/p/3342282.html?utm_source=tuicool&utm_medium=referral 现在正在学&l ...

  7. shell及脚本3——正则表达式

    一.正则表达式 1.1. 什么是正则表达式 正则表达式是处理字符串的方法,以行为单位,通过一些特殊符号的辅助,让用户可以轻易进行查找.删除.替换某特定字符串的操作. 1.2. 正则表达式与通配符的区别 ...

  8. json的场景应用与实战

    首先 要感谢慕课网的老师 地址:http://www.imooc.com/learn/68 下面我来开始总结: 什么是json的这些我就不多说了  不懂百度 <?php function cre ...

  9. 如何从Exchange邮箱数据库批量删除特定邮件

  10. JavaIO学习笔记(五)

    JavaIO前期准备 什么是同步 指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪 什么是异步 异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO ...