| Mohammed 的个人资料Dynamics AX日志留言簿网络 | 帮助 |
|
|
8月25日 Multi Threaded Programming in Dynamics AX 2009Mohammed RasheedEver wrote an application in dynamics AX, which processed task/operation in a sequence, even though the tasks/operations are mutually exclusive?? For example.. Consider the following code, which gives a list of Sales order and Purchase orders that that an item is present on: SalesLine salesLine; PurchLine purchLine; itemId itemid; ; Itemid = “myItem”; While select salesid from salesline group by salesid where salesLine.itemid == itemId { Info(strfmt(“Sales Order = %1”, salesLine.salesId)); } While select purchid from purchLine group by purchid where purchLine.itemid == itemId { Info(strfmt(“Purchase Order = %1”, purchLine. purchid)); } ... AX kernel executes the above code in sequence of occurrence, hence, in the example above, the salesOrders are queried and Only After this Task is completed, will the kernel execute the purchLine query. Would it not make sense to run both the queries simultaneously??? ...... it surely does! So how do we do it....the answer is, Threads! Threads are an immensely powerful way of improving performance by performing multiple operation as the same time (pseudo parallelism) and take full advantage of the multi core processors commonly available now... But Remember... “with great power comes great responsibility”. Threads should to used with extra extra caution. Not only are they considered to be unsecure, but they are also unpredictable! For example, if I call Thread1.run(); followed by thread2.run();, then there is no guarantee that thread1 will complete its operations before thread2. This would not be much of a problem, if the threads are performing task that are mutually exclusive (for example, one thread is querying the salesLine table, while the other thread is querying the PurchLine table). However, if the task are not mutually exclusive (for example, both the threads are writing to a shared resource), then the programmer explicitly needs to write code to handle these situations. Other platforms use semaphores to handle this problem. Semaphores are not native in dynamics ax, but can be easily built if required. For more information, google for Race condition in threads or Dinning Philosophers problem. In other platforms, threads are executed by extending an abstract class or implementing an interface, however in Dynamics AX, threads are objects of the class ‘Thread’. In the following example, I wrote some quick code to show you how we could query the purchLine Table and the salesLine table at (almost) the same time and then display the results. There is some code for state handling, but it can be greatly improved to fit the needs of a production environment. Note: There is a good Tutorial on threads in DynamicsAX. Look at the form Tutorial_Threads in the AOT. Elements in my project: Form/ mrThreadItemTransactions This is a simple form, that lets the user select an item from a drop down, and will populate 2 list (sales and purch), based on the result of thread execution. Class/mrThreadProcessor Has two methods, both accept a thread as a parameter, the thread holds the itemId that should be queried. Once the methods complete execution, they add the list of order to the thread and return the thread to the caller. Code: Form: public class FormRun extends ObjectRun { Thread salesThread; Thread purchThread; container salesCon; container purchCon; } .............. public void init() { super(); if(inventItem.valueStr()) { element.getPurchSales(); element.setPurchSales(); element.populatePurchList(); element.populateSalesList(); } } ............. void getPurchSales() { ExecutePermission perm; ; perm = new ExecutePermission(); if (!perm) { return; } perm.assert(); salesThread = new Thread(); purchThread = new Thread(); salesThread.removeOnComplete(true); purchThread.removeOnComplete(true); purchThread.setInputParm([inventItem.valueStr()]); salesThread.setInputParm([inventItem.valueStr()]); salesThread.run(classnum(mrThreadProcessor),staticmethodstr(mrThreadProcessor,getSales)); purchThread.run(classnum(mrThreadProcessor),staticmethodstr(mrThreadProcessor,getPurch)); CodeAccessPermission::revertAssert(); } ......... void populateSalesList() { int conL; ; salesList.clear(); // clear list conL = conLen(salesCon); while(conL >0) { salesList.add(conpeek(salesCon,conL)); conL--; } } ..... void populatePurchList() { int conL; ; purchList.clear(); // clear list conL = conLen(purchCon); while(conL >0) { purchList.add(conpeek(purchCon,conL)); conL--; } } ............... void setPurchSales() { ; try { // retry or wait till both the threads are processed if(salesThread.status() != 2 && purchThread.status() != 2) // Warning:: possible infinite look, use carefully throw Exception::Internal; // if status = 2, then that indicates that the thread has completed // execution (I believe, 1 indicates that the thread is inProcess) salesCon = salesThread.getOutputParm(); purchCon = purchThread.getOutputParm(); purchThread = null; salesThread = null; } catch(Exception::Internal) { retry; } } ............... public boolean modified() { boolean ret; ; ret = super(); if(inventItem.valueStr()) // Bad design: I should be check if //the condition holds in the called method, not (only) in the caller { element.getPurchSales(); element.setPurchSales(); element.populatePurchList(); element.populateSalesList(); element.redraw(); } return ret; } .... Classs static void getSales(thread _t) { salesLine salesLine; itemid itemId; container outContainer; if(_t.getInputParm()) itemid = conpeek(_t.getInputParm(),1); else { info("item not found"); return; } while select salesid from salesLine group by salesid where salesLine.ItemId == itemid { outContainer += salesLine.salesid; } _t.setOutputParm(outContainer); } .... static void getPurch(thread _t) { purchLine purchLine; itemid itemId; container outContainer; if(_t.getInputParm()) itemid = conpeek(_t.getInputParm(),1); else { info("item not found"); return; } while select purchid from purchline group by purchid where purchline.ItemId == itemid { outContainer += purchline.PurchId; } _t.setOutputParm(outContainer); }
my web site - www.dynamic-ax.co.uk
评论 (1)
引用通告此日志的引用通告 URL 是: http://dynamic-ax.spaces.live.com/blog/cns!13619E6948204DE3!354.trak 引用此项的网络日志
|
|
|