Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
This question was closed Nov 08, 2017 at 12:21 PM by Bunny83 for the following reason:

The question is answered, right answer was accepted. If you have more questions, ask a seperate question

avatar image
30
Question by $$anonymous$$ · Nov 30, 2012 at 07:51 PM · c#coroutinesthreading

Unity3D and C# - Coroutines vs threading

I'm developing a terrain generation system. The terrain is split up into smaller chunks which can be loaded and deloaded.

The problem is that the generation of the chunks can be a bit on the heavy side.

This can cause small noticeable lags as you walk around.

My first thought was to add threading support by doing all heavy calculations in a thread

(Since I know the Unity3D API is not thread-safe I kept all Unity related objects and calls out of the threading).

Problem is I can't find any way to invoke the thread method back to the main thread of Unity.

My second option it seems is to look into coroutines. From what I understand coroutines allows you to break from a method and return at a later frame to finish it.

(But would coroutines actually be effective for my situation then? For example, if I split the generation method up into 4 frames, would users with fast computers will be punished if their CPU's could have squeezed more per frame, or have I misunderstood something?)

I would love to hear your suggestions.

Comment
Comments Locked · Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Alturis2 · Jan 10, 2014 at 02:39 PM 0
Share

Very helpful answer and nice to see someone go through the trouble of filling in a complete usable base class for someone to use.

I have a related question though and it sounds like Coroutines will be the only way to go if you cannot access Unity API calls such as Instantiate(). I have a feature where the level expands as you play spawning prefab "rooms" while the player is playing. This creates large noticable frame spikes as each room is instantiated.

Is there some documentation somewhere that outlines which Unity API calls are thread safe and which are not?

avatar image Fattie Alturis2 · Feb 27, 2016 at 04:07 PM 0
Share

Absolutely no Unity API calls are thread safe. Unity is single-threaded and that's that.

avatar image Eric5h5 Fattie · Feb 27, 2016 at 07:29 PM 0
Share

That's not really true. You can use certain things like Debug.Log in a thread. All of the $$anonymous$$athf functions are fine, though you could debate whether that's "Unity API" or just $$anonymous$$ono, since they're mostly just wrappers for System.$$anonymous$$ath functions. In any case, if something is not thread-safe, Unity actively prevents you from using it, so there's no worry about accidentally using something in threads that you shouldn't.

avatar image Fattie · Feb 27, 2016 at 04:15 PM 0
Share

Hi @PastryGood fwiw in relation to your question about splitting a task over frames (in Update/coroutine) You just watch the time and give up until the next frame when you've spent too long on it. I put in an answer below to save someone some typing.

4 Replies

  • Sort: 
avatar image
102
Best Answer

Answer by Bunny83 · Nov 30, 2012 at 08:11 PM

That's quite simple ;) You should use a class which represents a threading job. This class will be initialized by the Unity main thread. Then you start a worker thread on a function of that class and let it do it's job.

Here's the important part: Of course you store this job somewhere on the Unity side and have the Update loop (or a coroutine) continously checking an "isDone" variable in your class which will be set by the worker thread when it's finished and when it stored all data it produced. It's important that you make the access to this isDone boolean thread safe since both threads will need to access it.

edit

I just took a closer look at my first (untested) example. Unfortunately you can't use lock on value types like a bool, so you need any kind of reference type as lock handle. I've made a small "framework" for a threaded job:

 public class ThreadedJob
 {
     private bool m_IsDone = false;
     private object m_Handle = new object();
     private System.Threading.Thread m_Thread = null;
     public bool IsDone
     {
         get
         {
             bool tmp;
             lock (m_Handle)
             {
                 tmp = m_IsDone;
             }
             return tmp;
         }
         set
         {
             lock (m_Handle)
             {
                 m_IsDone = value;
             }
         }
     }
 
     public virtual void Start()
     {
         m_Thread = new System.Threading.Thread(Run);
         m_Thread.Start();
     }
     public virtual void Abort()
     {
         m_Thread.Abort();
     }
 
     protected virtual void ThreadFunction() { }
 
     protected virtual void OnFinished() { }
 
     public virtual bool Update()
     {
         if (IsDone)
         {
             OnFinished();
             return true;
         }
         return false;
     }
     public IEnumerator WaitFor()
     {
         while(!Update())
         {
             yield return null;
         }
     }
     private void Run()
     {
         ThreadFunction();
         IsDone = true;
     }
 }

This would serve as base class. Just create a concrete Job class which overrides the ThreadFunction function and implement your code. Here's an example:

 public class Job : ThreadedJob
 {
     public Vector3[] InData;  // arbitary job data
     public Vector3[] OutData; // arbitary job data
 
     protected override void ThreadFunction()
     {
         // Do your threaded task. DON'T use the Unity API here
         for (int i = 0; i < 100000000; i++)
         {
             OutData[i % OutData.Length] += InData[(i+1) % InData.Length];
         }
     }
     protected override void OnFinished()
     {
         // This is executed by the Unity main thread when the job is finished
         for (int i = 0; i < InData.Length; i++)
         {
             Debug.Log("Results(" + i + "): " + InData[i]);
         }
     }
 }


This is how you would use the job class:

 Job myJob;
 void Start ()
 {
     myJob = new Job();
     myJob.InData = new Vector3[10];

     myJob.Start(); // Don't touch any data in the job class after you called Start until IsDone is true.
 }

 void Update()
 {
     if (myJob != null)
     {
         if (myJob.Update())
         {
             // Alternative to the OnFinished callback
             myJob = null;
         }
     }
 }

edit
I just added the WaitFor coroutine which allows you to easily wait in a coroutine for the thread to finish. Just use

 yield return StartCoroutine(myJob.WaitFor());

inside another coroutine. This can be used instead of calling Update manually each frame.

Comment
Comments Locked · Show 25 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Nov 30, 2012 at 09:10 PM 1
Share

A "small" update ;)

avatar image Bunny83 · Nov 30, 2012 at 09:26 PM 3
Share

Btw my solution is for a few really heavy tasks. If you have a lot small tasks, it's probably better to use a queue and one or multiple worker threads that run permanently and pick jobs from the queue. If there's no job they sleep for some time. Oh and if you use this, don't create more workerthreads as you have (free) cpu cores ;)

Usually to get most out of the threading you would bound each thread to a certain core, but i guess that's don't necessary since we just want to reduce hicups in the Unity main thread.

avatar image Lo0NuhtiK · Mar 13, 2015 at 04:06 PM 1
Share

Just wanted to say thanks @Bunny83 , this helped a lot.

+5000 Upvotes (or at least the one I can give, anyway)

avatar image Bunny83 · Jul 10, 2015 at 10:05 PM 1
Share

@thrmotta:
I just edited my answer and included a WaitFor coroutine. I've written this on my tablet, so I can't write a proper example right now ^^

avatar image GGeff · Feb 16, 2016 at 06:09 AM 2
Share

can use a volatile IsDone rather than locking for efficiency. and WaitFor() needs to be public to use the nested coroutine code you posted.

Show more comments
avatar image
7

Answer by Eric5h5 · Nov 30, 2012 at 08:16 PM

Coroutines aren't really appropriate for this. Everything is still run in the main thread in that case, and there's no effective way of distributing CPU usage, which is especially important considering that nearly everything these days has at least two CPU cores.

Comment
Comments Locked · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image $$anonymous$$ · Nov 30, 2012 at 08:18 PM 0
Share

I see :) Well coroutines are off the list then. I think it is generally kind of odd that Unity3D as the commercial engine it is does not make a (what in some cases) vital feature such as threading easily integrate into the engine, such a shame.

avatar image Fattie $$anonymous$$ · Feb 27, 2016 at 04:13 PM 0
Share

How much easier did you want it to be? All the code is above. All threaded program$$anonymous$$g is incredibly difficult, on all platforms and environments.

avatar image derekguenther · Mar 28, 2015 at 05:31 PM 0
Share

I know this is old, but thought I would ask in case Eric5h5 is still around - I think coroutines would work fine if your ONLY goal is to reduce hiccups in performance. Threading is probably the better choice because otherwise it will actually increase performance (your main game runs on the main thread, and the new stuff is built concurrently, as opposed to using the main thread to build the new stuff); otherwise, a coroutine which builds the new terrain but yields based on how much time has passed in the frame could also reduce the hiccups, could it not? A potential pitfall is that if your game is experiencing low FPS your new terrain might not be built in a timely fashion, but if you're having performance trouble you will need the extra performance from multithreading anyway. As long as your FPS is decent, coroutines actually ARE an effective way of distributing CPU usage.

avatar image
3

Answer by petersvp · Apr 23, 2015 at 01:38 PM

Let me ad my two cents as well. I am also making Minecraft-inspired voxel game but with smooth terrain. After various bench, I ended up implementing my entire voxels stuff directly in C++ with PolyVox, as a DLL. This way, the generation is lighting fast. C++'s DLL uses worker threads, the Boss-and-Employees pattern styles. It exposes C functions so Unity can request loading/unloading of chunks, checking for results and fetching meshes. A C# coroutine constantly polls the C++ library for "Job Results" each frame. If there is a mesh generated, this coroutine "imports" the mesh. The process is not so complicated, the threading model was more chalenging than sending of the meshes to Unity. I basically create byte array with vertex, index and splatting buffers, then in Unity generate the mesh and splatting maps.

Comment
Comments Locked · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Gaviali · Sep 16, 2015 at 09:18 AM 0
Share

Do you think the speed-up was due to heavy calculations made in C++ (PolyVox) or did the threading model itself also contribute? I'm asking because I'm looking for an alternative to TLP Dataflow that requires .NET 4.5 (Unity is .NET 3.5) and was thinking to implement an multi-threaded actor library myself in C++. But I don't know if it's worth the effort in comparison with implementing the actor model using System.Threading in C#.

avatar image
3

Answer by GGeff · Feb 16, 2016 at 01:12 PM

Can use a volatile IsDone rather than locking for efficiency.

Comment
Comments Locked · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Gru · Sep 01, 2016 at 05:19 PM 1
Share

I would never recommend such a thing.

Reasons outlined here: http://www.albahari.com/threading/part4.aspx#_The_volatile_keyword

and here: http://stackoverflow.com/questions/154551/volatile-vs-interlocked-vs-lock

It's way too risky, you have to remember never to do read-modify-write on the writer thread. Ins$$anonymous$$d, for such micro-efficiency it would be better to use Interlocked. https://msdn.microsoft.com/en-us/library/system.threading.interlocked(v=vs.110).aspx

avatar image GGeff Gru · Sep 04, 2016 at 03:00 AM 0
Share

You bring up a very good point - that volatile is no multi-threaded panacea. However, in this particular case I am suggesting removing entirely the getter and setter, and making a simple bool volatile. There won't ever be a chance in this application for a read-modify-write. The bool isDone is only ever read in one thread and written (with no read or modify) in another thread, so it should be quite safe if I've read your links properly.

avatar image Gru GGeff · Sep 04, 2016 at 09:32 AM 1
Share

I agree this case seems like one of those where using volatile would be justified.

Researching recently into this topic myself, I've found some confusion and misunderstanding about the true value of using it, even outside Unity circles. I wanted to post the links above to make sure people don't take it lightly and compile a solid reference about it.

While it's certainly a viable option, I would rather recommend using Interlocked like in $$anonymous$$SDN example above - seems more resistant to code change, that's all.

Follow this Question

Answers Answers and Comments

34 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

Illuminating a 3D object's edges OnMouseOver (script in c#)? 1 Answer

Delegates and "__ Can only be called from main thread" 2 Answers

Sprinting camera shake 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges