递增由多个进程共享的全局变量。
$SEQUENCE为多个进程获取同一全局变量的唯一(非重复)整数索引提供了一种快速方法。对于每个进程,$SEQUENCE分配一个整数值序列(范围)。对$SEQUENCE的后续调用将递增到该进程分配的序列中的下一个值。当进程使用其分配的序列中的所有整数值时,系统会自动为其分配一个新的整数值序列。$SEQUENCE自动确定要分配的整数值序列的大小。它为每个序列分配分别确定已分配序列的大小。在某些情况下,该序列可以是单个整数。
$SEQUENCE始终将整数值递增1。默认情况下,$SEQUENCE分配正整数,从1开始。但是,$SEQUENCE可以设置为负整数;负整数向零递增。如果$SEQUENCE设置为负整数,则后续调用可以将零指定为增量。将gvar设置为非整数数值会生成<ILLEGAL VALUE>错误。
$SEQUENCE用于当多个进程同时递增同一全局时使用。$SEQUENCE和$INCREMENT都可以执行此操作,但$SEQUENCE通常提供更好的性能。$SEQUENCE分配索引的顺序与$INCREMENT顺序不同。$SEQUENCE可以将递增的顺序范围分配给进程,而不是将单个整数递增分配给每个进程的$INCREMENT行为。这可以通过减少进程冲突和同步来显著提高性能。它还可以在插入记录时提高数据块性能,因为顺序记录ID是按进程分组的。
当进程调用$SEQUENCE时,会发生以下情况之一:
^gvar全局变量未定义,因为没有进程定义此变量。$SEQUENCE返回的整数将从1开始。^gvar全局变量上次由来自另一个进程的$SEQUENCE调用修改。$SEQUENCE返回的整数将从分配给另一个进程的序列之后的第一个整数开始。^gvar全局变量最后一次是由从任何进程调用的集合$SEQUENCE修改的。$SEQUENCE返回的整数将从$SEQUENCE设置的值之后的第一个整数开始。$SEQUENCE分配给进程的序列大小取决于内部时间戳。当进程第二次调用$Sequence时,Caché会将前一个时间戳与当前时间进行比较。根据这些$SEQUENCE调用之间的持续时间,Caché会将单个增量或计算出的增量序列分配给进程:
分配的序列为1:$SEQUENCE的行为类似于$INCREMENT。分配的序列大于1:$SEQUENCE使用此按进程递增的序列。每个进程使用其分配的序列,然后被分配一个新序列。例如,进程A和进程B都在递增相同的全局进程。每个进程第一次递增全局时是单个递增。下次每个进程递增全局时,Caché会比较两个$SEQUENCE操作并计算递增序列(该序列可能是一个整数)。在重新分配增量之前,后续的$SEQUENCE操作会用完这些每个进程的序列。这可能导致如下递增:A1、B2(设置时钟的单个递增)、A3(Caché比较A1和A3,将4、5、6、7分配给进程A)、B8(Caché比较B2和B8,将9、10、11分配给进程B)。全增量序列可以如下:A1、B2、A3、A4、B8、A5、A6、B9、A7、B10、B11。
如果进程没有使用其分配的所有序列,则剩余的数字将未使用,从而在递增序列中留下间隙。
以下示例显示了$SEQUENCE(当前序列号)返回的增量整数与gvar(分配的最高序列号)的值之间的差异:
/// d ##class(PHA.TEST.Function).SEQUENCE() ClassMethod SEQUENCE() { SET $SEQUENCE(^myseq)="" FOR i=1:1:15 {WRITE "increment:",$SEQ(^myseq)," allocated:",^myseq,! } } DHC-APP>d ##class(PHA.TEST.Function).SEQUENCE() increment:1 allocated:1 increment:2 allocated:2 increment:3 allocated:4 increment:4 allocated:4 increment:5 allocated:8 increment:6 allocated:8 increment:7 allocated:8 increment:8 allocated:8 increment:9 allocated:16 increment:10 allocated:16 increment:11 allocated:16 increment:12 allocated:16 increment:13 allocated:16 increment:14 allocated:16 increment:15 allocated:16 DHC-APP>zw ^myseq ^myseq=16一旦序列通过对$SEQUENCE(^gvar)的第一次调用启动,在该序列生存期内对gvar值的所有将来更改都只能通过调用`$SEQUENCE(^gvar)`来进行。使用任何其他函数或语句更改gvar的值会导致序列变得未定义。
可以使用SET $SEQUENCE取消或重置$SEQUENCE全局。SET $SEQUENCE重置全局变量并释放分配给其他进程的整数序列。
SET $SEQUENCE(^gvar)=""将杀死指定的全局节点,并通知所有具有缓存的$SEQUENCE数字的作业以清除其当前增量值。对$SEQUENCE的第一次调用将递增为1。SET $SEQUENCE(^gvar)=""仅杀死指定的全局节点;否则,将终止所有指定的全局节点。它不会杀死该节点的后代(如果有)。SET $SEQUENCE(^gvar)=n(其中n是整数)会将指定的全局节点重置为n,并通知所有具有缓存的$SEQUENCE数字的作业以清除其当前增量值。随后在所有作业上调用$SEQUENCE将使用新的n增量起始值。如果SET $SEQUENCE尝试将^gvar设置为小数,则会出现<ILLEGAL VALUE>错误。如果SET $SEQUENCE尝试将^gvar设置为非数字字符串,则^gvar设置为0。不能使用KILL ^gvar或SET ^gvar来杀死或重置全局$SEQUENCE,因为这些命令不会释放分配给process.0的整数序列。
包含要递增的整数值的变量。不需要定义变量;第一次调用$SEQUENCE会将未定义的变量定义为0,然后将其值递增为1。gvar值必须为正整数或负整数。
通常,gvar参数是一个全局变量,可以带下标或不带下标:^gvar。它可以包含扩展的全局引用。如果是下标的全局变量,则可以使用裸全局引用来指定它。
gvar参数可以是局部变量或进程专用全局变量。但是,由于$SEQUENCE供跨进程使用,因此在大多数情况下,这种用法没有意义。在局部变量或进程专用全局变量上使用$SEQUENCE与数字增量为1的$INCREMENT相同。下面描述的有关锁定,日记记录和事务回滚的$SEQUENCE限制不适用于局部变量或进程专用全球在局部变量或进程专用全局变量上使用$SEQUENCE具有与$INCREMENT相同的错误行为;这与全局变量上$SEQUENCE的错误行为不同,如下一节所述。
gvar参数可以是多维属性引用。例如,$SEQUENCE(..COUNT)。它不能是非多维对象属性。尝试递增非多维对象属性会导致<OBJECT DISPATCH>错误。
$SEQUENCE不能递增特殊变量,即使是可以使用SET修改的变量也不能递增。尝试递增特殊变量会导致<SYNTAX>错误。
$SEQUENCE返回的整数范围是-9223372036854775807到9223372036854775806(-2**63+1到2**63-2)。尝试在全局变量上使用超出此范围的整数设置$SEQUENCE会生成<ILLEGAL VALUE>错误。
在下面的示例中,全局变量上的$SEQUENCE可以设置为9.223372036854775800E18,但是将此数字递增超过范围限制会生成<MAXINCREMENT>错误。可以重复运行此示例以执行“慢增量”和“快增量”。请注意,本例中的“快速递增”可能导致在实际递增到范围限制之前产生<MAXINCREMENT>,因为$SEQUENCE试图分配超出范围限制的数字序列:
/// d ##class(PHA.TEST.Function).SEQUENCE1() ClassMethod SEQUENCE1() { TRY { SET rand=$RANDOM(2) SET $SEQUENCE(^bignum)=9.223372036854775800E18 IF rand=0 { WRITE "slow increments:",! FOR x=1:1:10 { WRITE $SEQUENCE(^bignum)," increment #",x,! HANG .5 } } IF rand=1 { WRITE "fast increments:",! FOR i=1:1:10 { WRITE $SEQUENCE(^bignum)," increment #",i,! } } } CATCH exp { WRITE !,"In the CATCH block",! IF 1=exp.%IsA("%Exception.SystemException") { WRITE "System exception",! WRITE "Name: ",$ZCVT(exp.Name,"O","HTML"),! WRITE "Location: ",exp.Location,! } ELSE { WRITE "unknown error",! } } } DHC-APP> d ##class(PHA.TEST.Function).SEQUENCE1() slow increments: 9223372036854775801 increment #1 9223372036854775802 increment #2 9223372036854775803 increment #3 9223372036854775804 increment #4 9223372036854775805 increment #5 9223372036854775806 increment #6 In the CATCH block System exception Name: <MAXINCREMENT> Location: zSEQUENCE1+7^PHA.TEST.Function.1 DHC-APP> d ##class(PHA.TEST.Function).SEQUENCE1() fast increments: 9223372036854775801 increment #1 9223372036854775802 increment #2 9223372036854775803 increment #3 9223372036854775804 increment #4 In the CATCH block System exception Name: <MAXINCREMENT> Location: zSEQUENCE1+14^PHA.TEST.Function.1这些类型的错误仅在递增全局变量时发生。
$SEQUENCE专门用于涉及多个并发进程的整数增量操作。$INCREMENT是更通用的递增/递减函数:
$SEQUENCE将整数递增1。$INCREMENT将任何数值递增或递减任何指定的数值。$SEQUENCE可以将递增序列分配给进程。$INCREMENT仅分配单个增量。SET $SEQUENCE可用于更改或取消定义(取消)全局。$INCREMENT不能用于SET命令的左侧。注意:$SEQUENCE和$INCREMENT只有在执行简单地递增数值的操作(如ID分配)时,才可以对同一全局变量使用$SEQUENCE和$INCREMENT。在同一全局上使用$SEQUENCE和$INCREMENT的任何其他用法都可能产生不可预测的结果,因此不建议使用。
$SEQUENCE使用特殊、高效的锁定技术,仅将$SEQUENCE调用与其他$SEQUENCE调用同步。尝试对$SEQUENCE使用的全局变量使用LOCK命令不会对$SEQUENCE产生任何影响。例如,假设进程1对^COUNTER执行锁定:
LOCK ^COUNTER然后假设进程2递增^COUNTER:
SET x=$SEQUENCE(^COUNTER)进程1持有的锁不会阻止进程2递增^COUNTER。