Search Unity

[RELEASED/FREE] Thread Ninja - Run co-routines on background thread

Discussion in 'Assets and Asset Store' started by ciela_spike, Mar 7, 2014.

  1. ciela_spike

    ciela_spike

    Joined:
    Jan 1, 2014
    Posts:
    3
  2. ZJP

    ZJP

    Joined:
    Jan 22, 2010
    Posts:
    2,646
    Thanks for the release.
     
  3. karthikrock

    karthikrock

    Joined:
    Sep 6, 2014
    Posts:
    3
    Hi, I am trying to load a RevMob banner Ad from the background thread but it doesnt work and crashes the android game.. This is how i do it:


    private static readonly Dictionary<String, String> REVMOB_APP_IDS = new Dictionary<String, String>() {
    { "Android", "MYID"},
    { "IOS", "copy your iOS RevMob Media ID here" }
    };
    static RevMob revmob;
    static RevMobBanner banner;


    public void Start ()
    {
    revmob = RevMob.Start(REVMOB_APP_IDS, "Main Camera");

    }



    public void PowerUpsButtonClick ()
    {

    // other code
    StartCoroutine (StartExamples ());

    }




    IEnumerator StartExamples()
    {

    Task task;
    this.StartCoroutineAsync(Blocking(), out task);
    yield return StartCoroutine(task.Wait());


    }


    IEnumerator Blocking()
    {
    LogAsync("Revmob loading banner");
    if( revmob != null) {
    banner = revmob.CreateBanner(RevMob.Position.BOTTOM, 0, 0, Screen.width, 170);
    }

    LogAsync("Jump to main thread.");
    yield return Ninja.JumpToUnity;
    banner.Show ();

    }


    The game crashes out and I get the error :
    10-31 14:51:12.496: E/dalvikvm(10886): JNI ERROR (app bug): accessed stale local reference 0x1d200001 (index 0 in a table of size 0)
    10-31 14:51:12.496: E/dalvikvm(10886): VM aborting
    10-31 14:51:12.716: E/MP-Decision(2179): num online cores: 2 reqd : 1 available : 4 rq_depth:0.000000 hotplug_avg_load_dw: 26
    10-31 14:51:12.716: E/MP-Decision(2179): DOWN cpu:1 core_idx:1 Ns:1.100000 Ts:190 rq:0.000000 seq:197.000000


    10-31 14:51:13.377: A/libc(10886): Fatal signal 6 (SIGABRT) at 0x00002a86 (code=-6), thread 12633 (GC_start_routin)



    Can you pls help me out on this one ?
     
  4. ciela_spike

    ciela_spike

    Joined:
    Jan 1, 2014
    Posts:
    3
    Hi, I think it's just not allowed to do this on another thread, you must change the UI on the main thread. Background thread is usually used for performing heavy computation.
     
  5. karthikrock

    karthikrock

    Joined:
    Sep 6, 2014
    Posts:
    3
    Hi Thanks for ur reply..

    Can you please give me an example as to what kinds of things can be performed by this library?
     
  6. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,453
    @Karthikrick, let's say you want to calculate lot of noise function from
    http://forum.unity3d.com/threads/68764-LibNoise-Ported-to-Unity
    You do something like this
    Code (CSharp):
    1.         for (int i=0; i<threadCount; i++) {
    2.             int min = i * iterations / threadCount;
    3.             int max = (1 + i) * iterations / threadCount;
    4.             this.StartCoroutineAsync (Compute (min, max));
    5.         }
    To split Compute amongst threadCount threads.

    Where Compute is this call to the beast that is noiselib
    Code (CSharp):
    1.     IEnumerator Compute (int min, int max)
    2.     {
    3.         Debug.Log (min + " - " + max);
    4.         for (int i=min; i<max; i++) {
    5.             perlins [i] = (float)perlin.GetValue (i, 0, 0);
    6.         }
    7.         computed++;
    8.         yield return Ninja.JumpToUnity;
    9. // do some Unity stuff like generate cubes based on noise value
    10.     }    
     
  7. kuchaku

    kuchaku

    Joined:
    Oct 14, 2014
    Posts:
    37
    Thank you for making this asset, Ciela Spike.This seems very useful and so few have tried it or commented on it.

    When I first learned of 'co routine' I originally thought they were something like this, 'co processing' a routine. Now they actually can and do, improving performance significantly over a regular co routine.

    Being able to jump in and out of the main thread is useful. If Unity's API isn't thread safe, something like this seems like a nice compromise. I'm actually a little curious as to why Unity itself wouldn't pursue a similar feature. C# isn't known for its light speed, multi cores can be very useful, simplifying them and making it as clear as possible when in a backing thread or the main thread seems very intuitive to me and goes well with the idea of more rapid development.
     
  8. kookyoo

    kookyoo

    Joined:
    Apr 19, 2010
    Posts:
    46
    Hi,
    First of all thanks a lot for sharing such great tool with us, it's pretty powerfull :)
    I'm trying some load tests using your system, and found that over 3 very hungry tasks at the same time cause a huge performance drop in Unity. I suppose it's related to one of the threads being executed on the same core as Unity's main thread.

    As we know that Unity uses cores 0 & 1 for most of it's operations, don't you think it could be usefull to be able to set affinity to the thread pool to avoid those cores ? I made some researchs but didn't found how to plug it easily in your system. So I really would like to have your opinion on this idea.

    Again, Thanks a lot !
     
    TooManySugar likes this.
  9. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    393
    Hi! I'm new to unity and programming in general (lone artist/designer), also the idea of threading is completely new to me. So, I'm having a bit of trouble understanding the concept behind the usage of the code (I've never used threading before and don't use coroutines too often)... Could anyone give me a basic explanation about the reason behind the workflow/the logic behind the code? About the background and foreground threads and the kinds of things I'm supposed to do in one but not the other?

    I'm sorry if I'm being too silly, but I really want to use this whenever I can but I'm having a hard time understanding when to use it and how to use it properly. But the idea of better performance is just too juicy to pass up. Also, would it be possible to use this with MEC (More effective coroutines)? it sounds like it would be a golden combination (MEC coroutines are twice as fast as unity's and don't create any GC).

    Anyway, any advice would be greatly appreciated.
     
  10. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,453
    @Alverik If bits of your game code does heavy calculation and you don't want your game framerate to drop or your game to freeze up while that's happening, you can run that bit of code on a separate thread. Then when you need to access the Unity API (for example to change the position of a gameobject, or refresh an array of particles), you jump to the main thread using
    Code (CSharp):
    1. yield return JumpToUnity();
    MEC is for spawning 1000s of coroutines, usually an indication that you're doing something wrong. I explain: if you have 1000s of characters doing stuff and display isn't the bottleneck, it'll be so hard to debug that you'll spend most of your time figuring out who does what, coroutines are awful when it comes to debugging. The better alternative is to centralize all your character actions, store states in big arrays and process all that in one loop, handling timing with counters. Added benefit is it's much much more performant.
     
    Alverik likes this.
  11. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    393
    Thanks, great info by the way, still haven't had to control such a huge amount of characters but that's handy to know. Still, I have a bit more questions. My main confusion is how this is going to be processed. The order. So, If, as I've understood, you start in the background thread, which is supposed to be used for heavy calculations, then when I use yield return JumpToUnity() will the next code be done immediately or will the system wait for the previous code to be done to run it? This confuses me because isn't the whole idea from threading to do two different things at the same time in separate threads? or am I misunderstanding how threading works or is used in unity?...

    Again I'm sorry, I've only started to learn C# like 3-4 months ago... So I'm still very green... (I did read a book about C once, but that was like 10 years ago...)
     
    Last edited: Aug 11, 2016
  12. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    26,245
    Best avoid subjects that are problematic for really experienced programmers then. Stick to main thread. Avoid co-routines. Instead do it normally and directly.

    When the game is finished, run the profiler to understand where to optimise. This will be surprising - it will generally be slow where you least expect it, and will be something that co-routines and threading wouldn't have helped with anyway. Those things seldom help unless people know precisely what their program's pressure points are.
     
    laurentlavigne and Alverik like this.
  13. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,453
    -Like Hippo says-

    Ill answer anyway to confuse you so you run away from this tricky topic: Ciela uses dotNET coroutine so all the stuff that you use in NinjaThread behaves the same: yield return JumptToUnity() is a yield so it waits until the previous operation is done plus a frame then executes the rest.
    Check out Ninja's doc and if your'e confused about timing and game loop, build some tests with Debug.Log("doing dis " + Time.time); because it's very hands-on stuff and all your questions can be answered by a few hours of you testing simple examples.

    For example do some permutations of:
    Code (CSharp):
    1. public UI.Text text;
    2. void Start()
    3. {
    4.     StartCoroutineAsync(ThreadedThing());
    5. }
    6.  
    7. IEnumerator ThreadedThing(){
    8.     Debug.Log("starting "+Time.time);
    9.     text.text ="I start";
    10.     yield return JumpBack();
    11.     Debug.Log("in a separate thread "+Time.time);
    12.     text.text ="I crash!"; // API access, should be commented out
    13.     var thing = 0;
    14.     for(int i=0; i<100000000; i++){
    15.         thing += Mathf.sin(i);
    16.     }
    17.     yield return JumpToUnity();
    18.     Debug.Log("finished without freezing the game "+Time.time);
    19.     text.text = "finished without freezing the game "+Time.time.ToString();
    20. }
    Play around commenting and re-ording code inside ThreadedThing and see what breaks. text.text will, 99.99% of unity API calls will, Debug.Log or Mathf. won't crap out - very hands on.

    Stepping into async execution without solid foundation in c# is playing with fire, and at least familiarize yourself with the unity unique gameloop: http://docs.unity3d.com/Manual/ExecutionOrder.html
     
    hippocoder and Alverik like this.
  14. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    393
    Thanks, I'll take both your tips. I'll definitely check out the docs and try testing giving the code a spin. I'll also try to limit it's use to processes I think are quite heavy. Or as Hippocoder said, I'll wait until I see what's making my game slow and see if the technique is applicable to the issue. Anyways, one way or another I want to learn how to use it right, so thank you both.
     
    hippocoder likes this.
  15. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    355
    What you said there is not really true.

    MEC is an improved implementation of Unity's coroutines. MEC has a range of extra features, runs faster, and uses less memory. In almost every case MEC coroutines will perform a lot better than the action arrays you are talking about here, laurentlavigne, since MEC is basically the same structure under the hood except it is also self-optimizing.

    You would want something like MEC if you wanted to be able to run coroutines from non-Monobehavior classes, were using them heavily, needed more features and speed, or wanted to stop the garbage collector from causing frame rate jitters. You would use something like Thread Ninja if your app is running really heavy computations and you want to be able to do that without causing framerate jitters.

    The two packages address different potential problems, so you have to ask yourself which of those problems you want to address, and keep in mind that if your answer is "none of those" then just use Unity's coroutines.
     
    Alverik likes this.
  16. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    393
    Yeah, I was thinking of using both anyways ;) (whenever they are necessary or applicable).
     
    Last edited: Aug 11, 2016
  17. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,453
    @Trinary the "self-optimizing" comment had me take a second look at MEC, is it RemoveUnused that you're talking about?
     
  18. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    355
    @laurentlavigne A quick overview of the structure is that each coroutine is a process that gets put into a (coroutine) process list. The processes run one after another for as long as they are alive. Any process that finishes gets culled from the list automatically. MEC saves processing time by leaving holes in its process list and RemoveUnused comes by occasionally and removes those holes.

    You were saying you could take all your possible actions and store them in a big array. An array like that would have to check for every possible action either every tick or every frame. You could upgrade such a structure with a system to register events if you liked, and then only process the events that were in use, but that would be basically reproducing a process pump. If you also took advantage of the yield return architecture then what you would have there would be a coroutine system. That's what MEC is: A highly optimized coroutine system.

    What I was saying is that a process pump is a self-optimizing structure when compared against an array of processes, and all coroutine systems are process pumps.
     
    Alverik likes this.
  19. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,453
    @Trinary I only use yield return in the context of unity coroutine, can you explain how those work?
    http://data:image/jpeg;base64,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
    (totally hijacking this thread in an awesome way)
     
  20. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    355
    I do get asked that a lot. I'm thinking of making a video going over that this weekend.

    yield return was created by the .net foundation in order to make foreach statements work. It's designed to return a list of elements one at a time. As soon as you use yield return in a function that returns an IEnumerator type then .net recognizes that and compiles the function differently. This different structure allows you to return a value to some code that will do something with that value and then pass control back to the IEnumerator function, which resumes executing where it left off.

    Coroutines take advantage of this unique property of being able to return multiple values and resume where they left off each time. So yield return, which was originally designed to return a value in the list, is being used instead to pass control back to the process pump. When the process pump later calls the IEnumerator function that function will resume executing where it left off. This makes it really intuitive to structure a function that will execute over multiple frames. One of the only downsides is that we have to use commands (like yield return or yield break) that don't seem very well named, since the whole structure was created for a completely different purpose.
     
    laurentlavigne and Alverik like this.
  21. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    393
    By the way, I'm very new to coroutines and I recently learned about WaitForSeconds. Previously, in my mobile project I was using InvokeRepeating to deplete a few stat meters/bars every some specified amount of time (similar to the sims), but I hear people say coroutines are better performant, so, should I change them to coroutines instead? I found this in a forum:

    Code (CSharp):
    1. StartCoroutine("Shoot");
    2.  
    3. IEnumerator Shoot() {
    4.      yield return new WaitForSeconds(5f);
    5.  
    6.      while (true) {
    7.          // shoot stuff
    8.          yield return new WaitForSeconds(2f);
    9.      }
    10. }

    The only thing is, I also have some code that cancels the invoke and restarts it in case Update() detects the time float gVar has been changed (which is meant to change the time on the fly)... but I guess, in the case that I change to coroutines, it would kind of be best if I capture the data in a float variable which I can then pass to the coroutine? or capture it directly inside the coroutine instead of update? (i'm guessing the second?) Anyway, my only worry is, If I change to coroutines won't there be a small delay when you change the time on the fly? (like using an special item, which for an amount of time will make your character get hungry more slowly) .

    Or should I just leave them as is? I haven't really profiled them, but they're just removing 1 from a 100 every X time, then updating a gVar tied to a meter/bar.
     
  22. knr_

    knr_

    Joined:
    Nov 17, 2012
    Posts:
    257
    How does this get around platforms that do not support multithreading, like WebGL?
     
    Alverik likes this.
  23. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    355
    Ok, this discussion is now way outside of the scope of this thread. I just posted here to make sure that my coroutine asset wasn't being misrepresented.

    @Alverik If you want me to answer your question in depth then please ask in my coroutine thread. The short answer is that Update gets run every frame, and even an empty update function has a non-zero cost, whereas WaitForSeconds (Unity) or Timing.WaitForSeconds (MEC) won't call your coroutine at all until the time has passed, so that's how it's faster for your case.
     
    Alverik likes this.
  24. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    393
    Sorry, I nearly forgot about it, because almost all the question had to do a bit with coroutines (and everyone here seems very savvy about them ;)).
     
  25. rickomax

    rickomax

    Joined:
    Jun 11, 2013
    Posts:
    427
    Isn't the following code suppose to throw an error?

    Code (CSharp):
    1. void Start () {
    2.    this.StartCoroutineAsync(MyCoroutine());
    3. }
    4. IEnumerator MyCoroutine() {
    5.   yield return Method();
    6. }
    7. IEnumerator Method() {
    8.   yield return Ninja.JumpToUnity;
    9.   yield return Ninja.JumpBack;
    10.   var x = this.transform; //should throw an error, but it will not, meaning it's back to Unity main thread
    11. }
     
    validname1 likes this.
  26. saravananparanthaman

    saravananparanthaman

    Joined:
    Apr 12, 2018
    Posts:
    3
    hi,

    unity version : 2017.4.11f1
    visual studio : Microsoft Visual Studio C# 2017
    platform : oculus go (Android Mobile/VR)

    My Code:

    Code (CSharp):
    1.  private IEnumerator SaveAsset(byte[] bytes, FileType type)
    2.         {
    3.             yield return Ninja.JumpBack;
    4.  
    5.             if (!File.Exists(pathDirectory))
    6.                 Directory.CreateDirectory(pathDirectory);
    7.  
    8.             string filePath = pathDirectory + "/"  + type;
    9.             using (FileStream fs = File.Create(filePath))
    10.             {
    11.                 fs.Write(bytes, 0, bytes.Length);
    12.             }
    13.             yield return new WaitForSeconds(0.1f);
    14.             yield return Ninja.JumpToUnity;
    15.  
    16.         }
    There isnt any lag on download code previous to this. After the download completion, there is lag on saving the asset to device. Anyway I inserted the above changes on the code, but doesnt seems to show any changes.

    Please help!!
     
unityunity