AX2012 X++编写的batch job必须首先编译成.net的CIL语言才能运行,预先编译的CIL比X++的解释型p-code速度要快。X++的代码在保存到AOT的时候自动编译成p-code,要把p-code编译成CIL需要执行AOT > Add-ins > Incremental CIL generation from X++,还有一个full CIL generation from X++,这个动作在安装系统时进行一次,编译生成的CIL以.netmodule形式的文件保存在类似目录C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin\XppIL\下。
可以使用Global ::runClassMethodIL()来以CIL方式运行X++代码,具体看下例:
class DemoClassCIL { } // Called by: main, countNestedLoopsContainer. public server static str countNestedLoops(int _numOfLoops) { int runningSum = 0, ii, kk; for (ii = 0; ii < _numOfLoops; ii++) { for (kk = 0; kk < _numOfLoops; kk++) { runningSum++; } } return "Final sum is: " + int2str(runningSum); } // Called by: countNestedLoopsWrapper. private server static container countNestedLoopsContainer(container _cNumOfLoops) { int runningSum = 0, ii, kk; int numOfLoops; str sSumInString; container cReturn; numOfLoops = conPeek(_cNumOfLoops, 1); sSumInString = DemoClassCIL::countNestedLoops(numOfLoops); return conPoke(cReturn, 1, sSumInString); } // Called by: main. public server static str countNestedLoopsWrapper(int _numOfLoops) { container cFromCIL; new XppILExecutePermission().assert(); cFromCIL = Global::runClassMethodIL ("DemoClassCIL", // Or use classStr function. "countNestedLoopsContainer", // Or use staticMethodStr function. [_numOfLoops] ); return conPeek(cFromCIL,1); } // Run this method, from the MorphX code editor, // or from a job under AOT > Jobs. public server static void main(Args _args) { int startTicksInterp, endTicksInterp; int startTicksCIL, endTicksCIL; str resultStrInterpreted, resultStrCIL; int numLoopsWanted = 987; // These first two calls ensure DLL files are loaded, // before we can do a fair comparison. DemoClassCIL::countNestedLoops(numLoopsWanted); DemoClassCIL::countNestedLoopsWrapper(numLoopsWanted); startTicksInterp = WinAPIServer::getTickCount(); resultStrInterpreted = DemoClassCIL::countNestedLoops(numLoopsWanted); endTicksInterp = WinAPIServer::getTickCount(); startTicksCIL = WinAPIServer::getTickCount(); resultStrCIL = DemoClassCIL::countNestedLoopsWrapper(numLoopsWanted); endTicksCIL = WinAPIServer::getTickCount(); Global::info(strFmt ("%1 (Interpreted: %2), (CIL: %3).", resultStrCIL, endTicksInterp - startTicksInterp, endTicksCIL - startTicksCIL )); }
Global::runClassMethodIL()函数返回container,所以countNestedLoopsContainer()使用container对真正的计算过程countNestedLoops()做了封装,main()方法中比较了直接运行X++和CIL的速度,记得运行前执行下AOT > Add-ins > Incremental CIL generation from X++,在我的环境中得到的结果是:
Final sum is: 974169 (Interpreted: 984), (CIL: 16).
可以看到CIL比解释型p-code要快很多。
需要注意的是动态运行X++的函数evalbuf和runbuf是不能编译成CIL的。从AOT中移除一些X++的方法后,要从CIL中移除相应的CIL代码需要执行full CIL generation,增量CIL generation不会从CIL中移除这些代码。系统必须成功执行一次full CIL编译才能运行服务、SSRS报表及批处理任务。在目前版本的AX中任何一个类的任何一个方法有错误就会导致整个CIL编译失败, Cumulative Update 2 for Microsoft Dynamics AX 2012 对此做了些修正,无效的P-CODE编译时会抛出异常,不会影响到余下代码的编译。
更多内容参见http://msdn.microsoft.com/EN-US/library/gg839855。