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

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

1 Like

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.

1 Like

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 :stuck_out_tongue:

Yes, I was aware about that and that’s why I asked about this very precise case : wait before execute time.

Invoke

1 Like

I’m using UniRx and it has quite nice support for async operations, which can be used to integrate with or replace coroutines with.

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 :wink:

I quit bothering with that a couple years back, did they ever fix the timer inconsistancy with invoke?

I wouldn’t touch System.Timers . The reason for that is because coroutine point of execution is known and strictly defined. See:

3228347--247692--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.

3 Likes

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.

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.

1 Like

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

1 Like

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!

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.

2 Likes

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.

3 Likes

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.

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.

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.

3 Likes

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.

1 Like

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.

2 Likes