Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Is it good or bad to use System.Timers.Timer instead of a Coroutine ?

Discussion in 'Scripting' started by Kiupe, Sep 21, 2017.

  1. Kiupe

    Kiupe

    Joined:
    Feb 1, 2013
    Posts:
    528
    Hi guys,

    Simple question, when you need to delay code execution, juste once, not repeating it, would it be better to use a Coroutine or simply use the System.Timers.Timer class ?

    I'm asking because delayed some code execution is a task that I , and I suppose a lot of people, need to do a lot and I often just go the easy way and use Coroutines. But Coroutines don't really have good reputation (I know, it's mainly the way people use them fault) so I'm wondering if a better solution exist.

    Thanks
     
    daxiongmao likes this.
  2. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,244
    I just set timer and wait in update. Sometimes I get lazy (for some button script that I will never have to touch again or something) and just use UnityEngine.Time.time and check for difference.

    I should add that I use coroutines only when I need to delay communication with external libraries.
     
    hippocoder likes this.
  3. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Well coroutines are not the easy way for one shots...People use coroutines so wrong. You fire up a coroutine its gonna sit there and wait till you let it do its function again.

    While you can stop a coroutine, they don't interact with unity objects, in fact you will make a mess of things. Coroutines in unity are best used to run something routine and regular while letting your normal game loop continue on its merry way instead of waiting for example a long for loop to finish. They are designed to be a copilot, not a fire and forget. If you insist on a fire and forget outside the main thread, then threading would probably be a better solution, just make a new thread, do your thing, then join back in.

    Coroutines are powerful, when used right, you can set them up to be a parallel process and help handle heavy loads while letting your game smoothly truck along. However you need to be careful using them, they are NOT thread safe, they are NOT even threaded (unless you make them that way), it is really advanced coding. I encourage people to learn them and play with them, but for mercy sake please don't use them in a product you release until you really know what you are doing with them.

    A better coding practice for what you are describing would be to think logically through the entire situation. Wait timers aren't so good in your main loop. However setting a variable to the current time then checking it on each update or fixed update for a difference to match a total time works good. (You start a timer, you hang your loop, unless the timer is threaded).

    Example

    private float startWatch;

    start() {
    startWatch = Time.time;
    }

    Update() {
    if(Time.time - startWatch >= yourFloatTimeToWait) {
    do something;
    }
    }

    Ok terrible code I know but I think it gets the point across. No hiccups for your game loop, timer will fire your something when its delay has passed.

    Also why are you delaying, usually there is something that you are waiting for, and that is why you need to wait, generally you can hook into that something and check is it alive, is it true, call your function on that objects awake. Just because threadrippers are out with 32 cores on desktops doesn't mean you should hammer them :p
     
    Last edited: Sep 21, 2017
  4. Kiupe

    Kiupe

    Joined:
    Feb 1, 2013
    Posts:
    528
    Yes, I was aware about that and that's why I asked about this very precise case : wait before execute time.
     
  5. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,007
    Invoke
     
    neginfinity likes this.
  6. mysticfall

    mysticfall

    Joined:
    Aug 9, 2016
    Posts:
    649
    I'm using UniRx and it has quite nice support for async operations, which can be used to integrate with or replace coroutines with.
     
  7. Kiupe

    Kiupe

    Joined:
    Feb 1, 2013
    Posts:
    528
    I made some research about that and read some articles and post in the Unity forum explaining that Invoke is based on Reflection therefore should be avoided.

    To be honest, I read a lot about all that stuff : Timer vs Coroutine vs Invoke vs Update but at the end I don't know who I should trust ;-)
     
  8. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    I quit bothering with that a couple years back, did they ever fix the timer inconsistancy with invoke?
     
  9. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,345
    I wouldn't touch System.Timers . The reason for that is because coroutine point of execution is known and strictly defined. See:
    https://docs.unity3d.com/Manual/ExecutionOrder.html

    execution order.png
    This is an incredibly useful chart. I'd suggest to print it, pin on the wall, and offer sacrifices to it every friday. Or something.

    System.Timers will be most likely operating outside of unity event loop and documentation says quite a lot about it moving between threads:
    https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx

    Meaning, simply accessing your objects from within System.Timers can create unpredictable effects and cause trouble.

    I do not recommend using those because of this. Basically, you wouldn't know what exactly your game is doing (or have done) when the timer fires. This is not a problem with coroutines.
     
    KelsoMRK, chelnok and Kiwasi like this.
  10. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Coroutine can cause thread dead, bad bad bad, go ahead look it up. Timer is a timer, its gotta run, unity is a single thread, you don't wanna stop that to wait on your timer, look it up. Invoke's main issue was always the timer is not consistant at all, can test that yourself pretty easy, Update is update, it happens everytime the game loop runs by, it is not consistant because it depends on how fast each loop of the code runs by. FixedUpdate is consistant, unless your physics updates stutter. Setting a time, checking that time vs current time well thats like looking at your watch.
     
  11. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Whaaaat, see this misconception is the whole problem with people throwing around the "just put it in a coroutine" idea. What is your coroutine gonna do, is it gonna change a variable, is it gonna do something to an object that exists? if so look out eventually you are gonna bump heads, coroutines are not thread safe, you should not access game objects with them, The times that the yeilds return is used so you can predictably know when the coroutine is going to execute its function again. They are great for things like spawn pools where you are just gonna fire off something new and not change anything existing, or specific interface operability that doesn't get updated from the main loop, like a side thread of number of connected network users to a pid for example. You really should not just throw coroutines in and out of normal operation of your game loop.

    To make a long story short, I don't know why this has to be shouted from the rooftops COROUTINES ARE NOT MULTITHREADED. You have to do other things to make them run in parallel, just starting a coroutine runs on the main thread and must be cooperative, must yeild control. It allows your main loop to continue but it can very well hang your main thread if it hangs. Ok so you think you got multithreading down cause you read a quick article on async coroutines, well now you are in the multithreading territory consider all of this:
    I sincerely hope you guys just throwing these things around willy nilly put a very strong EULA clause in your games saying you are not responsible for destroying peoples cpu's.
     
    p3k07 likes this.
  12. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,211
    Read his post again. He's not saying coroutines are multithreaded. He's saying System.Timer.Timers is multithreaded and the MSDN entry for the class confirms it. I've quoted it below with the important part bolded. Basically if you use the class in an application that is sensitive to which thread has execution, like Unity for example, be prepared for things to break.
    https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx
     
    Last edited: Sep 21, 2017
    neginfinity likes this.
  13. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Oh yeah, I was just the coroutine part its getting thrown around to new devs way too much and it is starting to worry me. However that is why I suggested Time.time stored, then compare to Time.time until its threshold. its a unity function so keeps it tidy, doesnt pause anything, just moves along unless its time. Not optimized sure, but its noob safe!
     
  14. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    And let's not forget that System.Timers represents real time and does not respect game time.

    Ultimately coroutines do the job fine most of the time. If you need something more sophisticated, write up a custom timer using Time.time in Update.

    Invoke also works, but it's usage is limited to the most simple cases.
     
    Ryiah and neginfinity like this.
  15. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,345
    Do everybody a favor and actually read posts while paying attention, before responding to them.

    Coroutines implement green threads. The point of coroutine is that it is NOT multithreaded. It is a good thing. You know exactly when it is gonna execute within the event loop relative to everything else. In an environment that interacts with a graphical API, it is pretty damn important to know from which thread your're running, and what the main thread is actually doing. So if a system timer fires in the middle of a different call, it can mess up internal state of your game, unless you properly multithread proof your app, which is error prone and has overhead.

    --edit--
    @Kiupe

    There are several scenarios that are naturally easier to implement with coroutines compared to normal code. For example, in a scenario where your UI displays a dialog box and waits till user clicks yes or no, it is easier to make this happen with coroutines, rather than making a spagetthi out of connected events, etc.

    The issue with coroutines is that they do not serialzie, and therefore are not subject to hot reload. Once hot reload happens, they start over. They're also harder to debug when they start nesting deeply. However, as long as user understand the limitations, coroutines are just another tool that can be used depending on circumstances.
     
    Last edited: Sep 21, 2017
    hippocoder, LiterallyJeff and Kiwasi like this.
  16. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Yeah I am sorry I perhaps glanced too much and didnt carefully read your statements. Please accept my humble apologies. That is true, coroutines are nifty in that they can bounce in and out of your pipeline easily. For a new dev that doesn't understand them however they are a good way to thrash, threadlock (wait chains), and they can cause a thread dead situation if you try to run a method that interacts with an object right out of the coroutine instead of waiting for its moment and swapping in to pass off its results. Putting that with what you said, basically use the yield, take that moment to "bring to front", pop in the results of its heavy calculations (preferably with getters and setters), then go to background again to do its next phase while "yielding" back to the main loop. They are wonderful when used correctly, unfortunately I see so much of "just coroutine man" that it gets used badly, and I didn't give you the respect you deserved because I let my frustration on that out on you.

    Multithreading is awesome, but you gotta be sooooo careful with it, thats a whole different ballpark, if the threads ever interact you gotta merge them at abosolutely the right time or bang boom computer brain fart haha.
     
  17. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Invoke works beautifully. I am not sure where that about them performing badly came from someone earlier. I have read some comparison stuff about other reflection methods that do terribly on performance. However invoke cruises right along in Unity. The problem I had with Invoke was, lets say I created a spell with a cast timer, the cast timer would always be 10 seconds, Invoke("spellEffectBlast",10); sometimes it would be 8.5 to 9 seconds, sometimes it would be 10.5+ seconds rarely ever exactly 10. I assume it has some ties to the update loop for timing, which causes some discrepency. Otherwise if that is not an issue there is no reason not to use it.
     
  18. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    What are you on about?

    Coroutines aren't multi threaded. So most of this this is just nonsense. The whole point of coroutines is they give the appearance of asynchronous behavior, without actually being asynchronous. Coroutines do have their own special problems and traps. But they are not anywhere near as complex to get right as multiple threads.
     
    mysticfall, Ryiah and Suddoha like this.
  19. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I know you stated yourself that they're not multi-threaded, but your texts always read the opposite.

    I'm not even sure what you're referring to about all the problems you mention, we're talking about Unity's coroutines. They run just on the main thread, just scheduled to a certain point in the update pipeline.

    It's also just another way to delay the execution and of course it's just somewhere in the pipeline of all events to be processed on the main thread. It's not supposed to wait exactly 10 seconds, depending on it's implementation within the engine.
     
    Ryiah likes this.
  20. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    Functions and loops are a good way to thrash, create race conditions (loops waiting on each other to finish), and so on. That doesn't mean we should avoid writing functions and loops.

    There are a whole lot of ways a new dev can find themselves in trouble. It doesn't mean we need to discourage the use of tools because they didn't understand how they were meant to be used.
     
    Kiwasi and Ryiah like this.
  21. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    My go to is to just add up the amount of time between updates until the amount of time I want to pass has gone, and then do my thing. I can't say it is the "best" method, but from my experience it leads to very few headaches or hard to find bugs down the road.

    Code (csharp):
    1.  
    2.  
    3. private float timeWaited = 0f;
    4. private float timeToWait = 2f;
    5.  
    6. void Update()
    7. {
    8.     doSomethingOneTimeButAfter2Sec();
    9. }
    10.  
    11. private void doSomethingOneTimeButAfter2Sec()
    12. {
    13.     if (timeWaited < timeToWait)
    14.     {
    15.         timeWaited += Time.deltaTime;
    16.  
    17.         if (timeWaited >= timeToWait)
    18.         {
    19.             WaitedLongEnough();  //Do it now!
    20.         }
    21.     }
    22. }
    23.  
    24.  
     
    zombiegorilla likes this.
  22. Errorsatz

    Errorsatz

    Joined:
    Aug 8, 2012
    Posts:
    555
    Not really sure what you're talking about, Xype; coroutines aren't particularly arcane to work with, they're certainly simpler than multi-threading.

    OP: I'd continue using Coroutines; the only case I'm aware they have a bad reputation is people running too many of them at once, and even that's only an issue if it causes performance problems.

    If you're using "do X after Y seconds" a lot, you can make a utility function for that:
    Code (csharp):
    1.  public static class Schedule {
    2.     public class Runner : MonoBehaviour { }    
    3.  
    4.     private static Runner _backer;
    5.     private static Runner Backer {
    6.         get {
    7.             if(_backer == null) {
    8.                 var go = new GameObject("Scheduler");
    9.                 GameObject.DontDestroyOnLoad(go);
    10.                 _backer = go.AddComponent<Runner>();
    11.             }
    12.             return _backer;
    13.         }
    14.     }
    15.  
    16.     private static IEnumerator RunAfter (YieldInstruction yi, Action act) {
    17.         yield return yi;
    18.         act();
    19.     }
    20.  
    21.     public static void AfterSeconds (float seconds, Action act) {
    22.         Backer.StartCoroutine(RunAfter(new WaitForSeconds(seconds), act));
    23.     }
    24. }
    25. ...
    26. Schedule.AfterSeconds(5f, () => ShowFanfare(Fanfare.Big));
     
    Last edited: Sep 22, 2017
    LiterallyJeff likes this.
  23. Kiupe

    Kiupe

    Joined:
    Feb 1, 2013
    Posts:
    528
    It's really great to have so many feedbacks. Thanks guys.
     
    neginfinity likes this.
  24. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Ok so right there, you are trying to say to do that so you can add timed functions to a coroutine. Your expressed solution is to create a game object whose sole purpose exists to interact with the coroutine. That part I enjoy, however.... each time you use Schedule.AfterSeconds(float, method) you are creating a new coroutine, you never destroyed your old one. It is still doing doing its thing, grabing and releasing control every (seconds) when its insertion time hits after those seconds. So you do it again you make another one, again and another one. That piles up, while they aren't "perfomrance" noticable in your profiler, do that for an hour or two and what do you get.....



    However, I think everyone is missing my point, yet proving it more all the time. While you can simply come back at me with oh but I will just send another method afterwards to yeild break; Or do a StopCoroutine(); Now that that is pre argued, great code! you used statics, an object to do the interactions, unless the method you pass in and out effects some other game object directly you have made a safe coroutine, that terminates after adding my previously stated break or stop. However, coroutines have a small overhead when they fire up (its very small yes, but you will count those ms to the penny when you get to polishing phases), they also produce some garbage to collect yucky.

    Now IF everything is safe, the method passed isnt for example forcing a monster to move, where a unity update may try to do that as well and cause some fun out of sync blooper videos for your youtube, and all is smooth, coroutine is stoped before making another, pat on back good job. BUT, did you really just start a coroutine, to make a method wait a few seconds before firing, just to stop the coroutine, adding more overhead, more garbage, and a whole lot more code that could have been done in in a couple of lines inside the main thread, just because you think you are cool with the coroutines? Got some bad news for ya, you didn't really stop that update from checking time every frame, you just added a buncha extra code to spin up an extra process to do the same thing, waitforseconds just checks over and over until those seconds pass and becomes true to run again.

    Since you insist on coroutine like a madman with limited knowledge on how to properly use them, I will give one good reason to use a coroutine. If you need to regularly make massive collections, like lists, which unity likes to brain fart over, that is a wonderful reason to set up a coroutine, tell it to make those lists. Stop using waitforseconds, yeild return null, all those silly just another update() things, and get with the WaitUntil() and and WaitWhile(), start a coroutine that handles a heavy load, that is pretty much just a function, and call it when needed, properly, let it run along side your game the whole time. All these iddy bitty coroutines creating, destroying, or oopsing and letting them pile up is silly. You are only overcomplicating your project to the point it will become unmanagable.

    And on the note with the Unity link telling all about how coroutines are predictable in when they interact with the game loop. Yes you are right, a single one does, but if you have more than one going, guess what, they are completely unpredictable on what order the coroutines will interact.

    To make all this short, read this one line, K.I.S.S. Keep it simple stupid, don't go building the empire state building when you can just use Time.time
     
  25. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    @Xype I think you are over exaggerating the complexity of them. They are a tool to write cleaner code, see them as mini workflows inside your domain code. You say they are not thread safe? Well since they execute on the main thread I would say they are.

    There are some things you should know however when dealing with them.
    For example if you are not the lifetime owner of the gameobject, for example in SteamVR the Wand will do setactive(false) on the gameobject when the Wand goes inactive. Any running Coroutine will stop executiing. We had some cleanup at the end of our co routine that did not run when the Wand became inactive.

    Coroutines are super nice in UI's. I wish Unity fixed so that click handlers automatically understood that it should treat any clickhandler that return IEnumerator as a coroutines That way we could do

    Code (CSharp):
    1. public IEnumerator SaveClick()
    2. {
    3.    var prompt = new PromptBox("Overwrite data?");
    4.    yield return prompt;
    5.    if(prompt.Result)
    6.       persistence.Save(data);
    7. }

    Today we need the extrastep

    Code (CSharp):
    1. public void SaveClick()
    2. {
    3.    StartCoroutine(DoSave());
    4. }
     
  26. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    @Xype you appear to have absolutely no knowledge about coroutines in Unity. You are making a fool of yourself. I suggest stepping out of the conversation and going and doing some research on how coroutines are implemented. Once you figure that out, we can have a proper conversation about their usecases.
     
    Suddoha and mysticfall like this.
  27. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Yeah starting them inside a game object and keeping them there is cool too if you destroy the game object naturally the coroutine dies with it.

    I am not overcomplicating it, sincerely, because you are telling people with the most basic of questions, how should I wait for 5 seconds 1 time.... to do a whole buncha lines of code, that can't pass refs, can cause things to go out of sync just like a multithread can even though its not taking advantage of a multiple thread, I mean poor guy the other day was just wanting to know what caused his spikes after doing the rollerball tutorial, and someones like put your stuff in a coroutine spawn pool system. This poor kid just got through his first lesson in development sheesh. However all it really was, was those nasty mesh colliders. Got him to remove the 2 of those in his game and replace with spheres boom fixed.

    I am not saying a few coroutines are bad, I am not saying don't use them, for god sakes do, but use them wisely, make sure you keep them cleaned up when done with them, heck once you got the basics down pat you can go into setting up real parallel multithreading with them.

    The ups, functions running and you don't gotta wait for them and stutter. If you manage them properly and make sure you don't leave stragglers laying around to suprise you (basically not only generate garbage but you gotta pick up after yourself too) they have great uses. You shouldn't just use them because they are there though. Would be interested to see a third party not in the arguement just make the most simple of game 2 versions, 1 using the coroutine to wait 5 seconds the other using the Time.time I mentioned, run that through the profiler. Provide the results. If a third party no funny business lol.

    There are times to use things and there are times you are just being silly. Also please teach a guy to set a variable before trying to get him to run control swapping applications. My worry is not in them being used, my worry is in people just willy nilly with them thinking they just work and then you have 20 coroutines ripping a single logical thread apart while coming back into the main program in random unpredictable order. This is where you start massive wait chains, thread locking, and out of sync issues due to things being set on objects in the wrong order.

    I don't know about you guys but I learned how to hello world before I learned how to for loop.

    No, they are not thread safe because they can most certainly cause thread blocking.
     
  28. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    I suggest you do some research on coroutines, all you have is ad hominem. Shall I start a massive list of links showing you how everything I have said is on point.
     
  29. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    @Xype

    Read up on Thread safty, a none blocking operation is not what thread safe is
     
    mysticfall likes this.
  30. Errorsatz

    Errorsatz

    Joined:
    Aug 8, 2012
    Posts:
    555
    Where are you getting this? That part straight-up doesn't happen, unless the coroutine has a never-ending loop in it. And they wouldn't show up as threads in that analyzer, because they aren't on a different thread! I think you may be confusing coroutines for something else.
     
  31. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,802
    Coroutines are where it's at.

    Here's a simple example.
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using UnityEngine;
    4.  
    5. // logs "did a thing" after 5 seconds
    6. public class Example : MonoBehaviour
    7. {
    8.     public void Start()
    9.     {
    10.         StartCoroutine(DelayedExecution(5f, PrintThing));
    11.     }
    12.  
    13.     public void PrintThing()
    14.     {
    15.         Debug.Log("did a thing");
    16.     }
    17.  
    18.     public IEnumerator DelayedExecution(float delay, Action action)
    19.     {
    20.         if(action != null)
    21.         {
    22.             yield return new WaitForSeconds(delay);
    23.             action();
    24.         }
    25.     }
    26. }
    For a more scale-able solution look at @Errorsatz reply.
     
    Last edited: Sep 22, 2017
  32. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    This... a thousand times. Should have marked 'coroutines in Unity' in a penetrant color, maybe that would make him realize he's generalizing coroutines too much.

    @Xype If you weren't hardly trying to prove your points, I'd leave this thread alone thinking you were a troll. But obviously you appear to come from a different programming background or context, in which coroutines may cause fatal behaviour like stack corruption and the like.

    But honestly, as stated so many times in this thread, they often favor cleaner code, as you describe sequential logic written in ... guess what, a visual and easy-to-understand sequence. If you were to implement a complex coroutine in your beloved Update method, you'd surely branch multiple times or use early-returns to "step" forward in your method.

    Now let's head on..

    Coroutines can finish in a controlled manner, and that's what they often do. You do not necessarily need to stop them, unless you programmed them in a way that you have to. But that's up to yourself.

    You're only half correct on that, but you totally do not take into account that you usually prevent this from happening by having some kind of mechanism to track whether you've already started the coroutine and handle the behaviour appropriately.

    I smell ignorance.

    Starting to argue about optimization here does neither prove something right or wrong what we're discussing about.

    This exactly proves what @Kiwasi has written above.
    "Out of sync" - well what are you referring to? As couroutines run on the main thread, all you could technically implement is having 2 kinds of movement logics being active at the same time. But oh wait - this can just happen as easily with multiple scripts that operate on the same GO.
    => This isn't an argument.

    Once again, coroutines run on the main thread to. They're simply polling a boolean property to determine whether to jump back in and "step forward" - have you ever written custom yield instruction?

    Like seriously, do you even read your own posts or do you just smash your keyboard and forget about it? Do you really think your "bragging" does help in any way to prove your points?
    In contrast to the majority of the community who kindly tries to help, you're just getting pretty ignorant and arrogant. Stay on topic, respect the others.


    I'd kindly redirect you to @Kiwasi's post.

    You're proving the point that you're totally not much into the topic...
    How does this differ in any way from the other use cases?
    You can ALWAYS replace update logic with a coroutine and vice versa.
     
    Last edited: Sep 22, 2017
    mysticfall, Kiwasi and chelnok like this.
  33. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    Here's an example of a blocking operation:

    Code (csharp):
    1.  
    2. while (true) {}
    3.  
    Here's another example:

    Code (csharp):
    1.  
    2. void KillMeNow(int i)
    3. {
    4.    KillMeNow(++i);
    5. }
    6.  
    Actually that last example will likely crash the application. It isn't application safe, much less thread safe! :D

    This has nothing to do with thread safety. Coroutines exist only on the main thread. They run only on the main thread. If you see a coroutine on another thread, you're doing something very very very wrong.

    Please stop talking about thread safety when talking about Coroutines, because you are confusing the issue.
     
    AndersMalmgren and Kiwasi like this.
  34. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Ok Kid, I lived it. I know what thread safety is. Hang a thread, kill a thread, dead lock, you mess up your program because your program was not thread safe at least in the classes you were using with threads. Just seriously read through the bash me comments here and take a deep concentrated thought. One guy saying they arent multi threaded.... another saying they are green threads. Well the green thread guy is right, but green threads are multi threaded. It doesn't have to be a native kernal thread to be multithreaded...look at your resource monitor sometime, Your processor certainly doesnt have hundreds of threads for you to run (well not yet, jeez those threadrippers) but you can thread is too braod and has been used for way too much over the last 20 some years. Now its threads of routines, threads of cores, threads of logical processors....shesh.

    Ok so just to stick my old man grey hair in this one last time for you poor c# mono starters that are just now getting to play with coroutines over the last couple of years....which guess what they are, a reitteration done in a very poor way of "green threads" that was what java called the user level multi threading in the mid 90's before they switched to native threads in java 2. However coroutines are kinda jacked, its to a java developer the dumbest implementation of enumerator every and thats all you get roflmao, thank goodness proper .net is coming, .net may be behind the game but they are much closer than this hacked up stripped down unity mono we have now. ANYWAY...

    I went way back digging for ya guys, matching up some dates, yep I know what threadsafety is, and a green thread can certainly be not thread safe, therefore a coroutine can certainly have the NOT THREAD SAFE phrase thrown at it. The reason Java moved from green threads to native threads, is you basically get all the downfalls with very little of the benefits. Though a rebirth has come over the last few years because you can spin up hundreds of little lightweight coroutine green threads to all do their own little thing from a core management application (Spatial OS, golang, kotlin, its a fad now) .....

    OK so Java 2 was released in December 1998, that was the version they switched from green threads to native threads.....

    Here is you a nice article from Aug 1998
    https://www.javaworld.com/article/2076747/core-java/design-for-thread-safety.html

    Oh heck gotta throw this one in there too, from March 1 1999, this one even more funny relatable because it was back when java was common to use mutate and enumerable to make its green threads haha. Oh and yep thread safety mentioned. Take a look at the code, it almost looks just like a unity coroutine....
    https://www.javaworld.com/article/2...cy/using-threads-with-collections-part-1.html


    *drops mic* enjoy
     
    Last edited: Sep 22, 2017
  35. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    What the hell are you talking about?
     
    LaneFox and Kiwasi like this.
  36. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,211
    Coroutines are basically cooperative multitasking. They're not threaded in the slightest.

    https://en.wikipedia.org/wiki/Cooperative_multitasking
    https://gamedev.stackexchange.com/questions/143454/unity-coroutine-vs-threads/143461#143461
    https://web.archive.org/web/2012041....com/2011/07/07/unity3d-coroutines-in-detail/
     
    Last edited: Sep 22, 2017
    Kiwasi likes this.
  37. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    It amazes me that this conversation even occurred.
    Coroutines run in the main thread.

    This is wrong. End of story. Full stop.

    So could any of your other code. Write an infinite loop and it hangs your thread. The Coroutine portion is irrelevant.

    Nothing goes out of sync. Every active coroutine is evaluated every frame at the same spot in the lifecycle. You can pass anything you want to a Coroutine. To wait 5 seconds you use the WaitForSeconds yield instruction and give it a value of 5. It's literally 1 line of code.

    The difference is so negligible that you'd have to get into the thousands of instances for it to make a difference. You also mentioned doing it "one time" so if you're using Time.time in Update you have to manage that "one time" state either with a boolean flag or by turning the component off when it finished.

    StartCoroutine is a Unity function too. The difference between pause and yield is important.

    Invoked methods run on the first frame that is past the declared time. So it won't be exactly the time you entered, but the closest "over" frame. It'll never be less than what you pass it. Sames goes for WaitForSeconds and using Time.time or accumulating Time.deltaTime in Update.

    Why on earth are you linking to 20 year old articles about thread-safe collections for a language that Unity doesn't support?

    Ultimately - Timers raise their events in another thread so if you need to interact with the game world you have to marshal that event back into the main thread. You don't have to do this with Coroutines.
     
  38. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    For the last time, coroutines don't start new threads. It's not even fair to call coroutines green threads.

    Unitys coroutines implementation looks like this in pseudo code.

    Code (CSharp):
    1. IEnumerator coroutine;
    2. float timer = 0;
    3. float nextTime = 0;
    4.  
    5. void Update (){
    6.     if (timer <= nextTime){
    7.         timer += Time.deltaTime;
    8.         return;
    9.     }
    10.     if(!coroutine.MoveNext()) Destroy(this);
    11.     timer = 0;
    12.     nextTime = 0;
    13.     if(coroutine.current is WaitForSeconds){
    14.         nextTime = ((WaitForSeconds) coroutine.current).value;
    15.     }
    16. }
    17.  
    No threading anywhere. As pointed out, there is nothin that can be done with coroutines that can't be done with Update. A coroutine is syntactic sugar for a timer in Update.

    Unitys implementation is slightly more sophisticated for performance reasons. But it's the same basic idea.
     
    Last edited: Sep 22, 2017
  39. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    What I want to know is... did @Kiupe get the answer they were looking for? :p
     
    LiterallyJeff likes this.
  40. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    @neginfinity's post way back at the start covers the OP best.
     
  41. mysticfall

    mysticfall

    Joined:
    Aug 9, 2016
    Posts:
    649
    I'm sorry, but that actually *proves* you don't have a soild idea as to what 'thread safety' really means. Running an infinite loop to hang a thread, for instance, has nothing to do with thread safety, and neither does using a coroutine in Unity.

    Honestly, you need to take a step back and ask if you have some wrong ideas when so many people who might be just as, if not more experienced as you say that you do.

    Just google up some articles about thread safety which might clear the concept for you and study it, then you might realize what nonsenses you've talking about the whole time.
     
  42. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    @Xype

    Before I leave, Thread safty is when two different Threads can access the same resource without data going corrupt or exceptions being thrown.

    A classic example is one thread Adds a element to a collection while another one iterates over it, this will crash if a concurrent collection was not used. Or if you do not lock access to the collection.

    Edit: Since Coroutines are not threaded they run on the Main thread this can never happen
    edit2: Above problem could happen if one coroutine starts to itterate the collecton then yield return inside loop and then another coroutine adds a item to that collection.
     
  43. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Depends.

    If you use a foreach it will invalidate the inumerator, which will throw an error.

    But a for or while loop a coroutine will happily iterate over a collection even while things are bring added or removed. In fact I'll commonly use this strategy with queue like collections. One coroutine can be popping while another is pushing without any issues.
     
  44. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Yeah I meant iterating over it, but if you index you end up with reading the same element twice etc, invalid state. Which is a huge problem :)
     
    Kiwasi likes this.
  45. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Sometimes people just get themselves ALL UPSET and need a nice drink, a comforting environment etc. I would recommend some retro music, perhaps.
     
  46. Xype

    Xype

    Joined:
    Apr 10, 2017
    Posts:
    339
    Funny you should say that, I just grabbed a couple retro 8 bit music packs and fiddled with all the suggestions here. Great results, the coroutine to wait 10 seconds hovered around 2-3 times the resources as the runner up on bad, which was mine, it used half the cpu as the coroutine process, winner, Invoke. around 60% of the resources mine used. Now thats cause this is just an easy fast method. Try to manage a collection like that, the coroutine will win every time because it gets the advantage of creating the list, dict, array whatever in a lighweight little process all by itself without the unity overhad bogging it down. Proper uses, not just cause you can. I ge4t due to the silly implementation you get stuck with it in some specific cases (like the one guy said how else you gonna enumerate that UI properly), but again its about best use.
     
    hippocoder likes this.
  47. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    It also just runs on the main-thread, so whatever you do there makes your frame-time longer, you can achieve the same result using no coroutines at all, without a significant difference in performance. As already stated, coroutines can be replaced by logic in Update, and vice versa.

    You're trying to tell people not to use coroutines for simple tasks, sometimes you argue with overhead, sometimes with all the problems you think they might introduce.

    Yet there's no difference between your example and the common usage of coroutines, which invalidates all your arguments you've been posting here. Well done, shot yourself in the foot again.
    Keep trolling.
     
  48. Kiupe

    Kiupe

    Joined:
    Feb 1, 2013
    Posts:
    528
    I think so :)

    Thanks
     
    BlackPete and LiterallyJeff like this.
  49. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    OK, so most of us are just amateurs playing around, so giving advice like don't use coroutines will probably result in unimaginable spaghetti code. That's the reason we have classes, etc, because it helps us simplify and makes our code more readable and easier to extend and debug. Sure, we could write it in c++, or plain c, or binary or something on our own and it would be faster, but that's not what we're here for. It's fast enough and the code is easier to read and debug.
     
  50. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    What you're saying makes absolutely no sense because you're not contextualizing it with the code you're actually executing and the results of the tests you're running. Talk is cheap. Show us what you're doing.