Search Unity

[FREE] More Effective Coroutines

Discussion in 'Assets and Asset Store' started by Trinary, Feb 23, 2016.

  1. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    I just published my implementation of coroutines which don't allocate memory on the heap every frame. Imagine that!

    Best of all, it's free.

    Take a look.
     
    Last edited: Mar 16, 2016
    NotaNaN, konsic, rakkarage and 9 others like this.
  2. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Based on user suggestions I'm adding exception handling and a static WaitForSeconds method. That will be out in the next few days.

    I'm also doubling the price, so hurry up and download it because 2 x $0 is.. umm.. still free.
     
    NotaNaN, hippocoder, ilmario and 3 others like this.
  3. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    I'm planning on changing the namespace to "MEC" on the next update. (the current namespace "MovementEffects" is the same namespace as my other asset, so it creates a conflict if both are in the project.)

    Does anyone see a problem with MEC as a namespace? Like, are there any existing popular assets that use that?
     
  4. S_Darkwell

    S_Darkwell

    Joined:
    Oct 20, 2013
    Posts:
    320
    @Trinary:

    I'm not aware of any popular assets that use the MEC namespace, but would still advise against something so short. Even if nothing exists currently, that doesn't mean that a popular asset in the future won't use it. Most assets tend to stick with namespaces at least 6 characters in length, preferably with a reference to both their asset and their company name (eg: TrinaryMEC).

    Just a thought!
    - S.
     
  5. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Well, I don't think that most people use UPPERCASE.. and MEC is not a valid domain name extension, so I'm still thinking I can get away with it.
     
    S_Darkwell likes this.
  6. S_Darkwell

    S_Darkwell

    Joined:
    Oct 20, 2013
    Posts:
    320
    Fair enough!

    - S.
     
    Trinary likes this.
  7. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    The new version is out with the namespace of MEC.

    Also, StartProcess was changed to StartCoroutine. I honestly can't say why I called it a process. It's not multithreaded, so it's not really a process. They're coroutines!

    Anyway, support was also added for handling exceptions. (it will now abort the coroutine that threw the exception, and leave the rest of them alone) Also, Timing.WaitForSeconds and Timing.StopCoroutine(coroutine) were both added. I'm still working on yielding one coroutine to another one. (it is tricky to do without using classes).
     
  8. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    Thanks a lot for the amazing work! Are the coroutines tied to the gameobjects that starts them?
     
  9. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    I have a quick plea for anyone who has used MEC: can you please leave a review or at least give it a star rating? I hate to have to ask like this, but the first 200 people who downloaded MEC left literally zero reviews. I know it feels like someone else will surely leave one, but it turns out that everyone assumes that.

    Also, that was a joke earlier about the price. I don't intend to start charging for the free MEC package that is currently released ever.
     
    Last edited: Jan 12, 2017
    PhoenixRising1 likes this.
  10. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    I did leave a star rating but I'll go ahead and leave a written review too. That's the least we can do for a free tool.
     
    Trinary likes this.
  11. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    That's a great question. All the MEC coroutines are tied to a central object named Timing. Timing is kind of like a singleton except that you can make more than one if you want. I've tried to explain it on the website http://trinary.tech/category/mec/

    Thank you.
     
    rakkarage and PhoenixRising1 like this.
  12. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437
    I didn't know normal Coroutines leaked memory? Does this happen everytime you start a coroutine? Does it add up over the lifetime of your game? Does it cause fps spikes like the garbage collector?
     
  13. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Every time you start a coroutine a pointer to your coroutine function is bundled along with any variables that you pass into it and stored on the heap for the GC to eventually clean up. This allocation is built into .net, so both MEC and Unity do that. Unity's coroutines also return a generic object from their yield returns, which have to be stored on the heap and collected by the GC later. MEC avoids this per - frame gc alloc (which is typically about .1kb per coroutine per frame).
     
  14. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    Correct me if I'm wrong but I don't think it's considered a memory leak, is it? Leaked memory is never collected as far as I'm aware.
     
  15. BTStone

    BTStone

    Joined:
    Mar 10, 2012
    Posts:
    1,422
    Yeah, afaik this is just produced garbage which is collected by the GC eventually.
     
  16. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    That's right. An actual memory leak is a huge problem that you can almost never create without jumping out of .net managed code.

    So, neither unity coroutines nor MEC leak memory in the technical sense of the word, but Unity's coroutines create a lot more memory for the garbage collector to clean up, and that GC alloc causes jitter in your game/app.
     
  17. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    I wouldn't use the word "just" there. Having the GC run every minute or two and randomly produce jitter is a HUGE problem for almost every commercial app. It degrades the user experience and makes your app look bad.
     
    PhoenixRising1 likes this.
  18. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437
    Interesting. Well, whenever I get into my "optimization" mode, I'll have to try to remember this. Seems like a decent optimization tool.
     
  19. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    I can't seem to get StopCoroutine to work.
     
    Last edited: Mar 3, 2016
  20. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Ok, I may need to put an example on the website. It needs to be the exact same instance in order to find a match. So you'll need something like this:

    var instPtr = MyCoroutine(1.0f);
    Timing.StartCoroutine(instPtr);

    ...

    Timing.StopCoroutine(instPtr);
     
    PhoenixRising1 likes this.
  21. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    Ah, there we go. Thank you.
     
  22. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Welcome

    It sounds like it would be helpful if StartCoroutine returned the instance pointer. Even though that's technically the same thing that you pass into StartCoroutine.. It would just make the code look cleaner.

    Thanks for exercising the new functions, ephemeral.
     
  23. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    I was just used to having to type StopCoroutine without linking to any instance. Always good fun to learn something new :).
     
  24. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    That's interesting. I might be able to change it to work that way using reflection. I'll put it on the todo list.
     
    PhoenixRising1 likes this.
  25. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    That would be amazing.
     
  26. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    I've gotten a report that UnityScript has trouble telling the difference between the static (for MEC) and non-static version (for Unity coroutines) of StartCoroutine that is attached to the Timing object. I'll make sure this is truly an issue before making any changes, but it looks like I may have to change the Timing.StartCoroutine function to Timing.StartUpdateCoroutine so that everything works in java.
     
  27. EliasMasche

    EliasMasche

    Joined:
    Jul 11, 2014
    Posts:
    92
    First thx for the great asset i use a lot of coroutine for my AI, so i hope that is going to improve the perfomance in my game if used very well :p.

    Second i have a problem when i try to create a new coroutine when i write IEnumerator is giving a problem, i upload a image showing the error. I added the MEC library but IEnumerator still calling to System.Collections for the coroutine.
     

    Attached Files:

  28. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    I can't tell from your screenshots, but do you have any yield return lines in your function? The compiler will treat the function like a normal function until you use yield return for the first time.
     
  29. EliasMasche

    EliasMasche

    Joined:
    Jul 11, 2014
    Posts:
    92
    ok sorry for that and i useyield return Timing.WaitForSeconds(), for start Timing.StartCoroutine()
    now i upload my script where i have the problem, the error is:
    CS0308: The non-generic type `System.Collections.IEnumerator' cannot be used with the type arguments
     

    Attached Files:

  30. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Thank you for the script. I had forgotten about this part: You need to include the System.Collections.Generic namespace for MEC coroutines. It appears that you can actually stop including System.Collections in many situations, since it's mostly being used just for Unity's coroutines. Not that it hurts anything to leave it in.

    I'm going to go add a note on the website about that now.
     
    EliasMasche likes this.
  31. EliasMasche

    EliasMasche

    Joined:
    Jul 11, 2014
    Posts:
    92
    No problem, and thx for the fast reply. And yep now is working with some improvements in short with my small tests, going to see with the project is growing.
     
  32. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Glad to help. If you wouldn't mind leaving a rating and maybe a review on the asset store, I would really appreciate it.
     
    EliasMasche likes this.
  33. EliasMasche

    EliasMasche

    Joined:
    Jul 11, 2014
    Posts:
    92
    Sorry for that i forgot about that, was working in my project and including to scripts. now leaved a rate and a review.
     
    Trinary likes this.
  34. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    Hey.
    I saw that you've updated the tool. Do you mind telling us what's new in it? :)
     
  35. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Sure. Three things:
    1. I got a report that UnityScript can't deal with having a static function and a non-static function that have the same name. So I had to make sure that all the static MEC coroutine functions didn't have the same names as the non-static Unity ones. This means I had to change StartCoroutine to StartUpdateCoroutine and StopCoroutine to StopMECCoroutine.
    2. When you do StopMECCoroutine it's now searching via the function's name rather than the reference. This is slower, but easier to use (as you pointed out, ephemeral). So StopMECCoroutine should now work like Unity's StopCoroutine.
    3. Someone left a negative review because they thought that StopAllCoroutines wasn't implemented. It could easily be accomplished before by calling "Destroy(Timing.Instance);" but now there's a function called KillAllCoroutines (once again, #1 made me have to use a different name) that calls destroy. I also put in helper functions for PauseAllCoroutines and ResumeAllCoroutines.
    Now that I've added a little functionality that isn't available in Unity's coroutines I'm thinking of also adding coroutine groups. They would basically be an optional string parameter that you could add to several functions. That would allow for an interface for making some groups timescale independent and also allow you to pause and kill groups together.
     
  36. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    Hey. Thanks for the detailed patch notes. Any chance you could allow us to stop a coroutine in both ways? I've changed my scripts to use the faster one without reflection and it's always great to have options. So maybe just call the reflection method StopReflectiveMECCoroutine or something like that. I think both methods have different uses.

    I love your tool, mad props to you for making this free.
     
  37. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    v1.3.1 is under review and will be out soon.

    Not many changes. I've updated the pdf documentation, changed StopMECCoroutine to just KillCoroutine, and I'm no longer using LongLength to index the coroutines for two reasons: #1 I don't think anyone really needs more than 2 million active coroutines, and #2 stripped down versions of .net don't seem to have LongLength defined.

    Anyway, enjoy.
     
  38. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Ok the new version is out, and it allows you to use it both ways. You can either pass in the type of your coroutine to stop the first instance of that type, or you can pass in a specific handle to stop that particular instance.

    Note: If the coroutine that you want to stop is the current one that you are running then you shouldn't use KillCoroutine, you should use yield break instead.

    For some reason the star rating on MEC has dropped to 4 stars. I don't know who is giving it low ratings, but I wish they would tell me why. If the plugin has helped you and you're reading this then please help me out by rating it on the asset store. Thank you.
     
    EliasMasche and PhoenixRising1 like this.
  39. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    I've read about trolls and competitors doing this, and I don't see any other reason it would decrease in rating. Thanks a lot for the update!
     
    Trinary likes this.
  40. EliasMasche

    EliasMasche

    Joined:
    Jul 11, 2014
    Posts:
    92
    Yes happens in assets, are simple trolls sometimes. thanks for the updates, is a great asset.
     
    Trinary likes this.
  41. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    495
    Great asset, when is plan to add nested co-routine feature?
     
  42. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    I have a plan for it, I'm hoping I can do it this weekend.

    Thanks for asking, it helps to know what features people still need. Btw, if anyone else has any features on a wish list, I'll be glad to hear them.
     
    PhoenixRising1 and idurvesh like this.
  43. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    495
    One more feature is like threaded co-routine, I see there is one available in asset store but its too old and uses Unity's coroutine so GC does get generated ,if you can come up with threaded coroutine in your asset or might just give us a way to use it with that asset would be super efficient,
    https://www.assetstore.unity3d.com/en/#!/content/15717
     
  44. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    495
  45. GiantGrey

    GiantGrey

    Joined:
    Jul 2, 2012
    Posts:
    268
    thank you for this free and great asset!

    +1 nested coroutine would be great!
     
    idurvesh likes this.
  46. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    Those are interesting links, thank you. Here's how I feel about threaded coroutines: Coroutines already solve 90% of the issue that multi-threading solves with 10% of the headache.

    I think that the beauty of coroutines is that they aren't multithreaded. When I was developing desktop apps 10 years ago the biggest problem we had by far was thread safety. There are so many counter-intuitive ways to get into trouble when you start messing around with threads.

    That said, it's very possible to poke that hornet's nest in Unity. It's actually really easy to create a threaded process and pass data around with thread safe buffers if you know what you're doing. If you don't know what you're doing then making coroutines look like threads is like making a stick of TNT look like a candle: Someone's going to get hurt, and I don't want to be responsible for that.

    With all that said, I do think that the one application that absolutely begs to be multi-threaded is for swarming (in all it's wonderful forms), which happens to be something that my non-free asset, Movement / Time, excels at. It's also far more easy to make the more structured framework of Movement / Time both multi-threaded and safe. So I do intend to look into it, but not for this asset.

    @propeller thanks for the vote. I'll keep it at the top of my to do list. ;)
     
    Last edited: Apr 7, 2016
  47. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    I have an implementation that yields one MEC coroutine to another. I'll be working on testing it today. yielding a MEC coroutine to a unity coroutine turns out to be no easy task, since the "coroutine" object that unity's coroutines return have no public api. I suppose I'll have to dig into the private api for that object. Hopefully I can access it without reflection.

    Anyway, I'll build a function to yield to a www object, Unity coroutine, and MEC coroutine. Are there any other objects that anyone would like to be able to yield to?
     
    idurvesh likes this.
  48. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    It looks like Unity's Coroutine object is handled entirely in unmanaged code, so I can't even access its methods via reflection. That means there will only be functionality to yield to MEC coroutines and www objects, and no way to automatically yield to Unity coroutines.

    Anyone who really needs to yield a MEC coroutine to a Unity coroutine will have to use a shared variable and a while loop that checks that variable every frame.
     
    idurvesh likes this.
  49. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    495
    Great work, when update would go live? does this means I can use nested MEC coroutines?
     
    Trinary likes this.
  50. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    395
    I don't know when it will make it through review, but I submitted it last night. Since it's uncompiled source it usually only takes a couple of days to review. I'll PM you the new version so you can tell me if you run into any errors.

    The solution ended up getting a little convoluted. I ended up needing an enum for the timing segment, so rather than do things one way internally and another way externally I changed the public API from StartUpdateCoroutine (and it's two cousins) to RunCoroutine that accepts the timing segment.

    I expect this to be the last major update to MEC. Not that I won't update, I'm not going anywhere, I just think that it does everything it needs to do now and will probably just work going forward. There aren't many external dependencies, it should just work no matter what version of Unity you're using.

    I'll be making some significant improvements to Movement / Time over the next few weeks. I plan to remove the dll, and I finally have a clear path to removing ALL GC ALLOCS.
     
    idurvesh likes this.