linzefei 发表于 2009-2-21 05:08:16

数组绑定系统

//======================================2009.2.24再次优化精简代码=======================
//======================同时改为单链表,减少2个数组======================================
2009.2.23 再次精简代码 减少了近一半代码量

前几天 aeris 和 cccty1l 讨论了很久的 hash 写法
看了帖子```受益良多 链接: http://bbs.wow8.org/thread-87418-1-2.html  http://bbs.wow8.org/thread-87523-1-1.html

于是我也写了个 数组绑定系统 
欢迎大家指出不足

PS:我是用WE Helper编写的 (它也有vj功能,。我只利用那个可以定义全局变量) 所以如果要使用的话 请把globals里的全局变量 用 变量编辑器设置好``同时代码里变量也需要意义修改(似乎好麻烦的说```) WE Helper下载地址:http://www.islga.org/bbs/read.php?tid=7677&fpage=7

或者 下载 数组绑定系统b3(普通WE移植版).w3x

再ps:里面还有个缓存系统``我拿那个来对比效率的。。。感觉似乎差不多。。。(单位狂加。加到卡``)
似乎别人说的  hash写法 都是缓存的n倍。。```也许我算法效率太低?希望各位帮忙 提出改进建议```

代码说明:
SetDataInt 储存整数      SetDataReal 储存实数       SetDataString 储存字符串 

例:call SetDataInt(整数A, 被绑定的handle类型数据B, 储存数据的名字c,要储存的整数d)
//A可以是任意数字(值被B覆盖);B,比如计时器,单位等;C要存的数据 名字叫什么;d 储存的数据。
//比如给单位udg_u 绑定数字174 名字叫"num" call SetDataInt(0,udg_u,"num",174)
// 实数 字符串的储存 获取 销毁 均以此类推

GetDataInt 储存整数      GetDataReal 储存实数      GetDataString 储存字符串
例:local integer i=GetDataInt(0,udg_u,"num")//取出前面存的那个174

DestroyDataInt 清除整数    DestroyDataReal 清除实数    DestroyDataString 清除字符串
例:call DestroyDataInt (0,udg_u,"num")//消除前面存的那个174

全部代码如下:
//======================================2009.2.24再次优化精简代码=======================
//======================同时改为单链表,减少2个数组======================================
globals
    handle D_H
    integer D_I
    integer Length=0
    integer Last=0
    integer array Last_Last
    integer array Data_H
    integer array Data_h
    integer array Data_Next
    integer array Data_Int
    real    array Data_Real
    stringarray Data_String
    boolean array Data_H_Int
    boolean array Data_H_Real
    boolean array Data_H_String
endglobals
constant function S2HI takes string i returns integer
    return i
    return 0
endfunction
constant function HI2S takes integer i returns string
    return i
    return null
endfunction
function SetData takes integer D_I,integer D_S returns integer
    local integer Li=(D_I+D_S)-(D_I+D_S)/8191*8191
    local boolean b=FALSE
    set D_I=D_I-D_S
    set D_S=Data_H
    if D_S!=0 then
      loop                     
      if Data_h==D_I then
            return D_S
      endif
      exitwhen Data_Next==0
      set D_S=Data_Next
      endloop
      set Li=D_S
      set b=TRUE
    endif      
    if Last!=0 then
      set D_S=Last_Last
      set Last_Last=0
      set Last=Last-1
    else
      set D_S=Length+1
      set Length=D_S
      if Length>8191 then
            return -174
      endif
    endif      
    if b then
      set Data_Next=D_S
    else
      set Data_H=D_S
    endif
    set Data_h=D_I
    return D_S
endfunction
function SetDataInt takes integer D_I,handle D_H,string Name,integer Data returns nothing
    set D_I=SetData(D_I,S2HI(Name))
    if D_I!=-174 then
      set Data_Int=Data
      set Data_H_Int=TRUE
    endif
endfunction
function SetDataReal takes integer D_I,handle D_H,string Name,real Data returns nothing
    set D_I=SetData(D_I,S2HI(Name))
    if D_I!=-174 then
      set Data_Real=Data
      set Data_H_Real=TRUE
    endif
endfunction
function SetDataString takes integer D_I,handle D_H,string Name,string Data returns nothing
    set D_I=SetData(D_I,S2HI(Name))
    if D_I!=-174 then
      set Data_String=Data
      set Data_H_String=TRUE
    endif
endfunction
function GetData takes integer D_I,integer D_S returns integer
    local integer Li=(D_I+D_S)-(D_I+D_S)/8191*8191
    set D_I=D_I-D_S
    set D_S=Data_H
    if D_S==0 then
      return -174
    else
      loop
      if Data_h==D_I then
            return D_S
      endif
      exitwhen Data_Next==0
      set D_S=Data_Next
      endloop
      return -174
    endif
endfunction
function GetDataInt takes integer D_I,handle D_H,string Name returns integer
    set D_I=GetData(D_I,S2HI(Name))
    if D_I!=-174 then
      return Data_Int
    else
      return 0
    endif
endfunction
function GetDataReal takes integer D_I,handle D_H,string Name returns real
    set D_I=GetData(D_I,S2HI(Name))
    if D_I!=-174 then
      return Data_Real
    else
      return 0.
    endif
endfunction
function GetDataString takes integer D_I,handle D_H,string Name returns string
    set D_I=GetData(D_I,S2HI(Name))
    if D_I!=-174 then
      return Data_String
    else
      return null
    endif
endfunction
function DestroyData takes integer D_I,integer D_S returns integer
    local integer Li=(D_I+D_S)-(D_I+D_S)/8191*8191
    local integer h=D_I-D_S
    local integer I=Data_H
    if I==0 then
      return -174
    else
      loop
      exitwhen Data_h==h
      if Data_Next==0then
            return -174
      endif
      set D_S=I
      set I=Data_Next
      endloop
      if Data_H_Int==FALSE and Data_H_Real==FALSE and Data_H_String==FALSE then
            set Last=Last+1
            set Last_Last=I
            set Data_h=0
            set D_I=Data_Next
            if Data_H==I then
                if D_I!=0 then
                  set Data_H=D_I
                else
                  set Data_H=0
                endif
            else
                if D_I!=0 then
                  set Data_Next=D_I
                else
                  set Data_Next=0
                endif
            endif
      endif   
                return I
    endif
endfunction
function DestroyDataInt takes integer D_I,handle D_H,string Name returns nothing
    set D_I=DestroyData(D_I,S2HI(Name))
    if D_I!=-174 then
      set Data_H_Int=FALSE
    endif
endfunction
function DestroyDataReal takes integer D_I,handle D_H,string Name returns nothing
    set D_I=DestroyData(D_I,S2HI(Name))
    if D_I!=-174 then
      set Data_H_Real=FALSE
    endif
endfunction
function DestroyDataString takes integer D_I,handle D_H,string Name returns nothing
    set D_I=DestroyData(D_I,S2HI(Name))
    if D_I!=-174 then
      set Data_H_String=FALSE
    endif
endfunction
/////////////////////////////////////////////////////////////////////////////////

donghailw 发表于 2009-2-21 13:48:04

很好很强大啊 橙子很辛苦

eff 发表于 2009-2-22 17:16:33

if I!=0 then
            loop                              
            if Data_h==D_I and Data_s==D_S then
                  if Data_H_Real==FALSE then
                        set Data_H_Real=TRUE
                  endif
                  set Data_Real=Data
                  return
            endif
            exitwhen Data_Next==0
            set I=Data_Next
            endloop
            set Li=I
            set b=TRUE
      endif
这个一定会死掉的。。。。。

linzefei 发表于 2009-2-23 03:04:25

没死掉过呢`````
我去测试下..要链多少个才会死掉``

http://bbs.wow8.org/viewthread.php?tid=88337&page=1&fromuid=101045#pid1186283
这里 aeris 帮我做了个性能测试

我做了一个性能测试,比较缓存和LZ写的Hash法的性能差异

测试1
对2200个location进行数据绑定操作,代码如下:



function Trig_TimedTest_Actions takes nothing returns nothing
    local integer i
    local location loc
    local integer watch
    local real time
   
    set watch = StopWatchCreate()
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      call cache.attachInteger(loc, "TEST", i)
         
      set i = i + 1
    endloop
   
    set time = StopWatchMark(watch)
    call StopWatchDestroy(watch)
    call BJDebugMsg("缓存绑定: " + R2SW(time, 5, 5))
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      call cache.clean(loc)
         
      set i = i + 1
    endloop
   
    call TriggerSleepAction(2.0)
   
    set watch = StopWatchCreate()
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      call SetDataInt(0, loc, "TEST", i)
         
      set i = i + 1
    endloop
   
    set time = StopWatchMark(watch)
    call StopWatchDestroy(watch)
    call BJDebugMsg("哈希绑定: " + R2SW(time, 5, 5))
   
    call TriggerSleepAction(0.0)
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      call DestroyDataInt(0, loc, "TEST")
         
      set i = i + 1
    endloop
   
    set loc = null
endfunction




这是某次的测试结果:
http://bbs.wow8.org/attachments/day_090221/20090221_fe763144da4cf6f2b59eOpzF20VFyDLS.png

对2200个location进行绑定操作,缓存用时大约0.09秒(平均),而Hash法用时0.025秒(平均)

测试2
在测试1的数据基础上,测试分别读取2200个绑定的数据,另外测试了空循环用时,以供对照

代码如下:


function Trig_TimedTest_Actions takes nothing returns nothing
    local integer i
    local location loc
    local integer j
    local integer watch
    local real time
   
    // 准备数据
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      call cache.attachInteger(loc, "TEST", i)
         
      set i = i + 1
    endloop
   
    call TriggerSleepAction(0.0)
   
    set watch = StopWatchCreate()
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      set j = cache.extractInteger(loc, "TEST")
         
      set i = i + 1
    endloop
   
    set time = StopWatchMark(watch)
    call StopWatchDestroy(watch)
    call BJDebugMsg("缓存读取: " + R2SW(time, 5, 5))
   
    call TriggerSleepAction(0.0)
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      call cache.clean(loc)
         
      set i = i + 1
    endloop
   
    call TriggerSleepAction(2.0)
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      call SetDataInt(0, loc, "TEST", i)
         
      set i = i + 1
    endloop
   
    call TriggerSleepAction(0.0)
   
    set watch = StopWatchCreate()
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      set j = GetDataInt(0, loc, "TEST")
         
      set i = i + 1
    endloop
   
    set time = StopWatchMark(watch)
    call StopWatchDestroy(watch)
    call BJDebugMsg("哈希读取: " + R2SW(time, 5, 5))
   
    call TriggerSleepAction(0.0)
   
    set watch = StopWatchCreate()
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
         
      set i = i + 1
    endloop
   
    set time = StopWatchMark(watch)
    call StopWatchDestroy(watch)
    call BJDebugMsg("*对照* 空循环:" + R2SW(time, 5, 5))
   
    call TriggerSleepAction(0.0)
   
    set i = 0
    loop
      exitwhen (i >= testLocArray.size)

      set loc = testLocArray<i>
      call DestroyDataInt(0, loc, "TEST")
         
      set i = i + 1
    endloop
   
         
    set loc = null
endfunction


测试结果如下:
http://bbs.wow8.org/attachments/day_090221/20090221_201c15a23530ba685204HRQ4RqOGO6VR.png
缓存读取大约0.023秒,哈希读取大约0.018秒,空循环本身耗时0.002秒

读取时,性能提高不大

linzefei 发表于 2009-2-23 03:20:57

测试过了.
完全不会死掉的...

globals
integer I=0
endglobals
function Trig____________________003_Actions takes nothing returns nothing
local integer D_I=174
local integer D_S=741
local integer Data=471
    call DisplayTextToPlayer( Player(0), 0, 0, "上次循环了 "+I2S(I) +" 次")
set I=0
            loop                              
            if Data_h==D_I and Data_s==D_S then
                  if Data_H_Real==FALSE then
                        set Data_H_Real=TRUE
                  endif
                  set Data_Real=Data
                  return
            endif
            exitwhen Data_Next==0
            set I=Data_Next
            endloop

endfunction

//===========================================================================
function InitTrig____________________003 takes nothing returns nothing
local integer i=0
loop
exitwhen i>8191
set Data_Next=i+1
set i=i+1
endloop
    set gg_trg____________________003 = CreateTrigger()
    call TriggerRegisterPlayerEventEndCinematic( gg_trg____________________003, Player(0) )
    call TriggerAddAction( gg_trg____________________003, function Trig____________________003_Actions )
endfunction


结果显示 第1次0
第2-3-4-5-....n次都是8192
而我的每1个链 都不可能会那么长的。。
而且``1个地图里 再怎么能存 ``最多也都存不到几千个数据的。。






2009.2.23 再次精简代码 减少了近一半代码量

灼眼のsaber 发表于 2009-2-23 07:02:18

使用缓存做0.02秒移动单位的函数没有这个的效率高么?

linzefei 发表于 2009-2-23 08:20:44

aeris 测试的是 存入 和 读取 的效率对比
按他的测试结果
这个存 比缓存高3-4倍
取 只高一点点

eff 发表于 2009-2-23 16:27:55

实际上你没有考虑全局变量和本地变量的区别。全局变量在跨度比较大的时候读起来会不定期变慢

linzefei 发表于 2009-2-23 21:57:41

全局变量在跨度比较大的时候读起来会不定期变慢

这点..不太理解..
有相关资料 给我看看么?

linzefei 发表于 2009-2-24 12:35:00

增加个 数组绑定系统b3(普通WE移植版)

eff 发表于 2009-2-24 13:09:25

很简单地,你对一个全局变量赋值1w次,和对1w个全局变量每个一次赋值,速度差N倍,然后如果你在一个触发里面对100w个以上的全局变量赋值,会直接被喀嚓掉,而对一个全局变量赋值100w次是没问题的。

zhuzeitou 发表于 2009-2-24 13:41:34

我怎么想到了page fault………………

对同一个变量赋值因为地址不变,不会产生page fault,对不同变量赋值,地址是变化的,总会产生page fault,极大地影响了执行速度………………

linzefei 发表于 2009-2-24 16:50:44

按汇编来说.
对 同1个变量赋值时 寄存器 只要存1次变量地址
然后在寄存器 存个数据 之后移动数据进地址


而对不同变量 那需要每次多出 寄存器存变量地址的步骤?``

那.`````....我改单链表好了.....稍微省点操作````````其他的也就这样了..反正经测试 ``实际效果比缓存快

eff 发表于 2009-2-24 17:00:29

缓存的问题不在速度,主要是会出现诡异问题

血戮魔动冰 发表于 2009-2-24 17:04:00

诡异问题?
万望LS披露一下~~~

linzefei 发表于 2009-2-24 17:26:51

字符串那些``

~~不过据测试这个确实是快了那么点....

eff 发表于 2009-2-24 18:33:05

你去重复生成字符串然后往缓存里面扔,大概仍4k个字符串缓存就挂了,而且字符串存进去,flushStoredXX删不掉

linzefei 发表于 2009-2-25 01:21:38

那么继续减少运算量``改单链 少存个字符串句柄``

261001126 发表于 2009-2-25 21:09:27

这是为什么呢?~ 为什么呢

linzefei 发表于 2009-2-25 23:33:15

什么为什么呢 为什么什么呢
页: [1] 2
查看完整版本: 数组绑定系统