Posted by patrickbateman on Tue, 15 Sep 2009 20:29:38
Hello everyone. I've been reading WoWProgramming and I've accomplished a lot of stuff with my addon (RhadaTip) also thanks to it! I was now adding a quite heavy (CPU speaking) function to my addon. I remember seeing in another mod (Routes) an option to decide whether to call a very CPU intensive computation of Routes in Foreground (thus locking wow entirely, but resulting in a shorter computational time) or in Background (thus resulting in a slightly less responsive wow, but definitely not a blocked one, and longer computational times before having the result).
I imagine that it will be something very hard to accomplish for me, but I thought that I'd try asking, I would love to give the user that choise myself. I have the book right next to me if you feel like pinpointing me toward a page in particular that I should re-read.
Posted by jnwhiteh on Wed, 16 Sep 2009 07:12:40
What you are looking for is coroutines, and they are not covered anywhere in the book. There are very few applications that find them useful and so we decided against including them in the book. They're a very advanced topic that doesn't have general use to an addon developer.
Here's an example of how you might do something like this. Now mind you, I haven't compiled this, but it should produce 10 print statements to the chat frame, spread out over 5 seconds. You can see the for loop is very simple, it just uses coroutines to yield and then re-resume:
local co = coroutine.create(function() for i = 1, 10 do print(i) coroutine.yield() end end) local frame = CreateFrame() local counter = 0 local throttle = 0.5 frame:SetScript("OnUpdate" , function(self, elapsed) counter = counter + elapsed if counter >= throttle then counter = counter - throttle if coroutine.status(co) ~= "dead" then coroutine.resume(co) end end) -- Actually start the coroutine coroutine.resume(co)
Posted by patrickbateman on Wed, 16 Sep 2009 07:58:43
Thanks for pointing me toward the right direction, between your example and this that I've now found out I hope that I'll be able to get it right!
Posted by jnwhiteh on Wed, 16 Sep 2009 08:04:45
The basic concept is that you create a coroutine.. do some amount of work and then voluntarily yield. Then at a later time (using an OnUpdate in WoW), you resume the coroutine to do some more work. They can be complicated.. but really do make things like this easier since the code you're writing stays the same.. you just chuck a few yields in there =)
Posted by patrickbateman on Wed, 16 Sep 2009 11:01:11
I think that I've got how to make it work (can't wait to be back home tonight!).
If I judge that my task (in your example, the print(i)) is fast enough under 100 iterations, I add something like:
for i=1, N if i % 100 == 0 then yeld() end -- do the main stuff (like print(i) in your example) end
This ensures that yeld is only called after what I consider to be an acceptable number of iterations, instead of after each one.
Then there is the throttle value I guess. Is there a magic value that should be used in order to give the user the impression that nothing is going on?
Thanks once again for the great support, between this and the hooksecurefunc thingy you really helped me so much!
Posted by jnwhiteh on Wed, 16 Sep 2009 15:33:50
Posted by patrickbateman on Thu, 17 Sep 2009 09:35:33
It works!! Thanks a lot!