全局变量 / 任务变量 / 锁
SPL 变量有三种作用域:局部变量、全局变量、任务变量。默认变量都是局部变量,作用域在同一个 SPL 脚本的范围内(不含主子线程代码),用法比较简单,本文不涉及。下面重点讲另两种变量,以及与之相关的锁。
全局变量
SPL 中全局变量的作用域是同一个 JVM(计算节点 \SPL 服务)的生命周期,在这个 JVM 运行的所有 SPL 脚本中都能访问到。
全局变量使用 env 函数赋值:
>env(gv1,1) //gv1 是全局变量名:
在脚本中直接用变量名访问就可以了
=gv1+2 // 等于 3
也可以删除:
>env(gv1)
有些数据可能会被多个脚本共享,在内存容量许可时预加载进内存,避免每次临时读取,从而提高性能。
服务启动时在 init.splx 加载全局变量。
A |
B |
|
1 |
=connect("orcl") |
连接数据库 |
2 |
=A1.query@x("select OrderID,Client,SellerID,OrderDate,Amount from orders order by OrderID") |
|
3 |
=A2.index() |
建立索引 |
4 |
>env(orders,A3) |
全局变量赋值 |
在脚本中就可以直接使用它
A |
B |
|
1 |
=orders.select(OrderDate>=arg1 && OrderDate<arg2) |
直接引用全局变量 |
2 |
=A1.groups(Client; sum(Amount):s,count(1):c) |
任务变量
有时一个复杂任务可能需要多个脚本共同配合才能完成,这些脚本可能会共享一些信息,总是通过脚本的参数和返回值来传递会比较麻烦,简单的想法就可以使用全局变量来实现。
但是,一个服务器可能同时并发很多任务,如果使用全局变量,会造成这个变量对所有任务共享,这常常不是我们想要的。
为此,SPL 提供了任务变量的机制。
一个 SPL 脚本(包括无脚本的 SPL 代码)发起,通过 call 函数执行的多个脚本完成的一次计算称为一个任务。同一个 JDBC 的连接,由多个 SPL 脚本共同完成的一次计算,也认定为一个任务。
任务变量的用法和全局变量类似,赋值时加一个选项 @j 即可:
>env@j(jv1,1) //jv1 是任务变量名
在脚本中直接用变量名访问:
=jv1+2 // 等于 3
也可以删除:
>env@j(jv1)
比如,主脚本将作为参数的用户名设置为任务变量 userID,子脚本使用 userID 进行计算。不同的任务(以不同参数执行的主脚本)下,userID 的值会不一样,互相不会影响。
主脚本
A |
B |
|
1 |
… |
|
2 |
>env@j(userID, arg) |
将 userID 设为任务变量 |
3 |
=call("sub.splx") |
子脚本 |
4 |
… |
sub.splx:
A |
B |
|
1 |
=connect("orcl") |
|
2 |
=A1.query@x("select deptID,deptName from account where userID=?",userID) |
使用任务变量 |
3 |
… |
锁
多个线程同时读写一个共享资源时,会导致不可预知的结果,比如某一个线程将共享变量从 1 修改成 2 再加 3,预期得到结果 5,但在执行加 3 的前一刻,另一个线程将该变量修改成了 4,此时前一个脚本继续将该变量加 3,将得到错误的结果 7。这种情况下可以用锁来保证并发读写的正确性,某个脚本对共享资源进行写操作前可以先上锁,其他脚本如果此时试图读写该资源,就必须等待前一个脚本解锁该资源,或者等待一段时间后放弃读写该资源。
比如,全局变量 m 用来记录某个文件被访问的次数,该文件会被多个脚本并发访问,为了避免读写冲突,应当使用锁。
A |
B |
|
1 |
=file("d:/Orders.csv") |
访问文件 |
2 |
>lock(10) |
上锁,锁名是 10 |
3 |
=m=m+1 |
访问次数加 1 |
3 |
>lock@u(10) |
解锁 |
4 |
=A2.import@t().select(Amount>arg1 && Amount<arg2) |
脚本被同时执行时候(假设 2 线程并发,m 初值 =0),如果不使用锁,两个线程里的 m+1 可能同时执行,都是 0+1=1,最终结果是 1,结果显然错误;使用锁之后,两个线程里的 m+1 必须分别执行,先上锁的先执行,0+1=1,前者释放资源后后者再执行,此时 m=1,所以 m+1=2,得到的结果正确。有时候前一个线程迟迟没有释放资源(甚至发生死锁),本线程不能无限等待,这时就要使用函数 lock 的第 2 个参数超时时间,意即本线程最多等待 N 毫秒,如果之前锁住资源的其他线程在这期间解锁了,函数 lock 将返回锁名,本线程应当正常锁住该资源并使用;如果其他线程超过 N 毫秒也没解锁,函数 lock 将返回 0,本线程应当进行意外处理。
英文版