找回密码
 点一下
查看: 4606|回复: 31

数组绑定系统

[复制链接]
发表于 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倍。。```也许我算法效率太低?希望各位帮忙 提出改进建议```

代码说明:[jass]
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[/jass]

全部代码如下:
[jass] //======================================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
    string  array 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[Li]
    if D_S!=0 then
        loop                     
        if Data_h[D_S]==D_I then
            return D_S
        endif
        exitwhen Data_Next[D_S]==0
        set D_S=Data_Next[D_S]
        endloop
        set Li=D_S
        set b=TRUE
    endif      
    if Last!=0 then
        set D_S=Last_Last[Last]
        set Last_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[Li]=D_S
    else
        set Data_H[Li]=D_S
    endif
    set Data_h[D_S]=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[D_I]=Data
        set Data_H_Int[D_I]=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[D_I]=Data
        set Data_H_Real[D_I]=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[D_I]=Data
        set Data_H_String[D_I]=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[Li]
    if D_S==0 then
        return -174
    else
        loop
        if Data_h[D_S]==D_I then
            return D_S
        endif
        exitwhen Data_Next[D_S]==0
        set D_S=Data_Next[D_S]
        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[D_I]
    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[D_I]
    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[D_I]
    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[Li]
    if I==0 then
        return -174
    else
        loop
        exitwhen Data_h[I]==h
        if Data_Next[I]==0  then
            return -174
        endif
        set D_S=I
        set I=Data_Next[I]
        endloop
        if Data_H_Int[I]==FALSE and Data_H_Real[I]==FALSE and Data_H_String[I]==FALSE then
            set Last=Last+1
            set Last_Last[Last]=I
            set Data_h[I]=0
            set D_I=Data_Next[I]
            if Data_H[Li]==I then
                if D_I!=0 then
                    set Data_H[Li]=D_I
                else
                    set Data_H[Li]=0
                endif
            else
                if D_I!=0 then
                    set Data_Next[D_S]=D_I
                else
                    set Data_Next[D_S]=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[D_I]=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[D_I]=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[D_I]=FALSE
    endif
endfunction
/////////////////////////////////////////////////////////////////////////////////[/jass]

数组绑定系统b.w3x

38 KB, 下载次数: 27

数组绑定系统b2.w3x

31 KB, 下载次数: 16

精简了代码

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

32 KB, 下载次数: 18

数组绑定系统d.w3x

30 KB, 下载次数: 16

数组绑定系统d(普通WE移植版).w3x

31 KB, 下载次数: 27

评分

参与人数 1威望 +64 收起 理由
kook + 64 打开了..

查看全部评分

发表于 2009-2-21 13:48:04 | 显示全部楼层
很好很强大啊 橙子很辛苦
回复

使用道具 举报

发表于 2009-2-22 17:16:33 | 显示全部楼层
if I!=0 then
            loop                              
            if Data_h[I]==D_I and Data_s[I]==D_S then
                  if Data_H_Real[I]==FALSE then
                        set Data_H_Real[I]=TRUE
                  endif
                  set Data_Real[I]=Data
                  return
            endif
            exitwhen Data_Next[I]==0
            set I=Data_Next[I]
            endloop
            set Li=I
            set b=TRUE
      endif
这个一定会死掉的。。。。。
回复

使用道具 举报

 楼主| 发表于 2009-2-23 03:04:25 | 显示全部楼层
没死掉过呢`````
我去测试下..要链多少个才会死掉``

http://bbs.wow8.org/viewthread.p ... d=101045#pid1186283
这里 aeris 帮我做了个性能测试
我做了一个性能测试,比较缓存和LZ写的Hash法的性能差异

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

[jass]

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

[/jass]


这是某次的测试结果:


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

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

代码如下:
[jass]

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
[/jass]

测试结果如下:

缓存读取大约0.023秒,哈希读取大约0.018秒,空循环本身耗时0.002秒

读取时,性能提高不大
回复

使用道具 举报

 楼主| 发表于 2009-2-23 03:20:57 | 显示全部楼层
测试过了.
完全不会死掉的...

[jass]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[I]==D_I and Data_s[I]==D_S then
                  if Data_H_Real[I]==FALSE then
                        set Data_H_Real[I]=TRUE
                  endif
                  set Data_Real[I]=Data
                  return
            endif
            exitwhen Data_Next[I]==0
            set I=Data_Next[I]
            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
[/jass]

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






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

使用道具 举报

发表于 2009-2-23 07:02:18 | 显示全部楼层
使用缓存做0.02秒移动单位的函数没有这个的效率高么?
回复

使用道具 举报

 楼主| 发表于 2009-2-23 08:20:44 | 显示全部楼层
aeris 测试的是 存入 和 读取 的效率对比
按他的测试结果
这个存 比缓存高3-4倍
取 只高一点点
回复

使用道具 举报

发表于 2009-2-23 16:27:55 | 显示全部楼层
实际上你没有考虑全局变量和本地变量的区别。全局变量在跨度比较大的时候读起来会不定期变慢
回复

使用道具 举报

 楼主| 发表于 2009-2-23 21:57:41 | 显示全部楼层
全局变量在跨度比较大的时候读起来会不定期变慢

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

使用道具 举报

 楼主| 发表于 2009-2-24 12:35:00 | 显示全部楼层
增加个 数组绑定系统b3(普通WE移植版)
回复

使用道具 举报

发表于 2009-2-24 13:09:25 | 显示全部楼层
很简单地,你对一个全局变量赋值1w次,和对1w个全局变量每个一次赋值,速度差N倍,然后如果你在一个触发里面对100w个以上的全局变量赋值,会直接被喀嚓掉,而对一个全局变量赋值100w次是没问题的。
回复

使用道具 举报

发表于 2009-2-24 13:41:34 | 显示全部楼层
我怎么想到了page fault………………

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

回复

使用道具 举报

 楼主| 发表于 2009-2-24 16:50:44 | 显示全部楼层
按汇编来说.
对 同1个变量赋值时 寄存器 只要存1次变量地址
然后在寄存器 存个数据 之后移动数据进地址


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

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

使用道具 举报

发表于 2009-2-24 17:00:29 | 显示全部楼层
缓存的问题不在速度,主要是会出现诡异问题
回复

使用道具 举报

发表于 2009-2-24 17:04:00 | 显示全部楼层
诡异问题?
万望LS披露一下~~~
回复

使用道具 举报

 楼主| 发表于 2009-2-24 17:26:51 | 显示全部楼层
字符串那些``

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

使用道具 举报

发表于 2009-2-24 18:33:05 | 显示全部楼层
你去重复生成字符串然后往缓存里面扔,大概仍4k个字符串缓存就挂了,而且字符串存进去,flushStoredXX删不掉
回复

使用道具 举报

 楼主| 发表于 2009-2-25 01:21:38 | 显示全部楼层
那么继续减少运算量``改单链 少存个字符串句柄``
回复

使用道具 举报

发表于 2009-2-25 21:09:27 | 显示全部楼层
这是为什么呢?~ 为什么呢
回复

使用道具 举报

 楼主| 发表于 2009-2-25 23:33:15 | 显示全部楼层
什么为什么呢 为什么什么呢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-11-23 21:45 , Processed in 0.117859 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表