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. 项目自动化建构工具gradle 入门0——环境 & 废话

    gradle 是一个项目自动化构建工具.同类的产品还有ant ,maven等等.相比之下我更喜欢gradle,它语法简洁.兼容maven.ide集成很好. 学习使用gradle最快的方式是看文档,而且 ...

  2. python 高级之面向对象初级

    python 高级之面向对象初级 本节内容 类的创建 类的构造方法 面向对象之封装 面向对象之继承 面向对象之多态 面向对象之成员 property 1.类的创建 面向对象:对函数进行分类和封装,让开 ...

  3. redis3.0常用命令

    1.服务器启动 1)快捷启动 $redis-server 2)指定配置文件启动 $redis-server redis.conf 2.客服端启动 1)快捷无密码启动 $redis-cli 2)有密码和 ...

  4. codevs 1052 地鼠游戏

    1052 地鼠游戏 http://codevs.cn/problem/1052/ 题目描述 Description 王钢是一名学习成绩优异的学生,在平时的学习中,他总能利用一切时间认真高效地学习,他不 ...

  5. [EF2]Sneak Preview: Persistence Ignorance and POCO in Entity Framework 4.0

    http://blogs.msdn.com/b/adonet/archive/2009/05/11/sneak-preview-persistence-ignorance-and-poco-in-en ...

  6. 神奇的BFC以及被忽略的东西

    BFC是CSS中一个非常重要的概念,经常用来清除浮动以及处理外边距折叠,但BFC到底是个什么东西却很难准确的表达清楚,国内的相关技术文档基本都不全面,本文的目的就是对BFC的方方面面做个整理,当然未必 ...

  7. eclipse环境搭建

    百度经验http://jingyan.baidu.com/article/bea41d437a41b6b4c51be6c1.html 1.JAVA JDK 2.Andriod SDK eclipse里 ...

  8. celery 框架

    转自:http://www.cnblogs.com/forward-wang/p/5970806.html 生产者消费者模式 在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据 ...

  9. [教程]phpwind9.0应用开发基础教程

    这篇文章着重于介绍在9.0中如何开发一个插件应用的示例,step by step来了解下在9.0中一个基础的应用包是如何开发的.1.目录结构OK,首先是目录结构,下面是一个应用我们推荐的目录. 应用包 ...

  10. python venv下安装mysql出错 解决方法

    1.首先使用exe文件安装python-mysql.链接: http://pan.baidu.com/s/1kVqILTX 密码: manj. 2.虚拟环境创建后,我们把已经在公共环境使用exe安装好 ...