Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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 /
avatar image
0
Question by RandomJ · May 02, 2018 at 02:26 PM · coroutinesasynchronousprogress bar

How to update a progress bar for ANY asynchronous operation?

I'm not talking about loading a scene, I'm talking about ANY kind of asynchronous operation.

To be specific, I need to read a file and to go through very long iterations with some heavy calculus, and I'd like to have a progress bar showing the progress of this operations.

Unity is not thread safe, and I don't fully understand how coroutines work.

Can somebody help?

Comment
Add comment
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

2 Replies

· Add your reply
  • Sort: 
avatar image
3

Answer by TreyH · May 02, 2018 at 09:01 PM

I think the most common way to make a progress bar is to bastardize the Slider UI Control. After that, you could just hook up a coroutine to update your slider as it ran through some lengthy operation.

 IEnumerator HeavyCalculus(int ticks) {
     var yieldInstruction = new WaitForEndOfFrame();
  
     for (float k=0; k < ticks; k++) {
         
         this.slider.value = k / ticks;
         yield return yieldInstruction;
     }
 }


As for coroutines, you can read up on them in the official docs, or watch Unity's youtube guide on them.

Comment
Add comment · Show 6 · 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 RandomJ · May 03, 2018 at 01:17 PM 0
Share

The problem with coroutine solutions is that you have to be specific about the amount of operations you want to do in a single frame, and I don't want that.

For instance: I don't want to read one (or n) line(s) from a file, update the progress bar and then wait for the end of the frame. It would considerably slow down the file read process. I want to read AS $$anonymous$$ANY LINES AS POSSIBLE, update the progress bar and then wait.

That's what I mean by asynchronous operation, and I don't believe I can do it by means of coroutines. Or am I missing something?

avatar image TreyH RandomJ · May 03, 2018 at 01:40 PM 1
Share

"The problem with coroutine solutions is that you have to be specific about the amount of operations you want to do in a single frame"

That is not the case at all. You don't need to use WaitForEndOfFrame as your yield instruction. There are several kinds of yields available to you during coroutines. See here.

How you break up a large task is up to you as the developer. If you want to set up a system where you read 100 lines then wait a few seconds, coroutines can do that trivially.

Alternatively, if you're looking for something that will just do some enormous / async task without clear breakpoints, then you could always use the native C# ThreadStart / Thread setup, but then you would need to either 1- fake a progress bar using whatever breakpoints your operation did have, or 2- relay that task's progress to some external monitor which then feeds a progress bar.

avatar image Bunny83 RandomJ · May 03, 2018 at 03:27 PM 1
Share

Well "processing as much as possible" is a bad criteria. Just run your for loop until it's complete within a single frame and you get "as much as possible" on a single thread. Of course your frame rate will drop to 0 at that point. Coroutines are not asynchronous at all. They implement synchronous cooperative multitasking. If a coroutine does not "cooperate" it will block just like a normal method would. Perfor$$anonymous$$g heavy tasks on the main thread and keeping a "good" frame rate is always a balance between how much work you can do to not drop below a certain framerate. This is generally significantly worse than "as much as possible".


Yes balancing work with a coroutine is quite difficult. Depending on the actual work using threads is the better approach

avatar image Harinezumi · May 03, 2018 at 01:46 PM 1
Share

Yes, coroutines and/or threads are the way to go for long operations.
+1 for bastardizing Sliders... they also make pretty good health bars :D

avatar image willisuh · Jul 29, 2019 at 05:40 PM 0
Share

i tried this but it says

ArgumentException: method return type is incompatible

avatar image Bunny83 willisuh · Jul 30, 2019 at 12:28 PM 1
Share

Because you probably did not return "IEnumerator" which is required for a coroutine. So the error you mentioned certainly is not related to the code presented in the answer.

avatar image
0

Answer by RandomJ · May 05, 2018 at 03:18 PM

Solved:

I have a progress variable, a lock, a thread and a coroutine.

Inside the thread, I lock the progress variable and update it at each iteration. Inside the coroutine, I check if the thread is running, lock the progress variable and update the progress bar.


Code snippet for whoever may be interested:

         public string FileName;
         public int MaxRows;
 
         private Thread _thread;
         private Object _locker;
         private float _progress;
     
         void Awake() {
             _thread = new Thread(LoadFromFile);
             _locker = new Object();
             _progress = 0;
         }
     
         private void Start() {
             GUIManager.Instance.ProgressBar.Begin();
             _thread.Start();
             StartCoroutine(LoadingRoutine());
         }
     
         IEnumerator LoadingRoutine() {
             while (_thread.IsAlive) {
                 lock (_locker) {
                     GUIManager.Instance.ProgressBar.SetProgress(_progress);
                 }
                 yield return null;
             }
     
             GUIManager.Instance.ProgressBar.End();
         }
     
         void LoadFromFile() {
     
             StreamReader reader = new StreamReader(FileName);
     
             string line = reader.ReadLine();
     
             for (int i = 0; (line = reader.ReadLine()) != null && i < MaxRows; i++) {
     
                 //...
                 //some heavy stuff here
                 //...
 
                 lock (_locker) {
                     _progress = (float)i / MaxRows;
                 }
             }
         }

EDIT: It's even simpler than that. It appears that you don't need to lock when doing operations with simple types, because they already are atomic. I just tried without locks and it still works.

Comment
Add comment · 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 RandomJ · May 05, 2018 at 03:24 PM 0
Share

Sorry if my question wasn't clear. I now updated it from "how to implement" to "how to update", 'cause that was the real question.

avatar image Bunny83 · May 06, 2018 at 01:37 AM 2
Share

Don't be deceived. Just because a type is a primitive type doesn't mean operations are automatically atomic. For example the i++ operator is not an atomic operation. It's a read-modify-write operator and those 3 steps are not executed as an atomic operation. However you have to think about what can actually go wrong. As soon as two or more threads can write the same value you get an actual race-condition. However when you only have one thread actually writing a value while another one is exclusively reading it you can't get any data corruptions. The worst thing that can happen is that the reading thread doesn't get the latest value in some cases. Though this doesn't matter in the case of a progress value.


Your reasoning is actually a fallacy. Just because it works without a lock doesn't mean it's working in general. That's the main issue with threading that you can't just test run it to verify it's safe. You have to use logical reasoning only. If you can't do this, better be safe than sorry and use a lock.

avatar image RandomJ Bunny83 · May 06, 2018 at 08:14 AM 0
Share

I didn't say that primitives operations are atomic because I tested it, I wanted to say that I heard they are atomic so I tested it. But yeah, I was incorrect: in CLI, simple reads and writes on primitive types in native word size are atomic, not any operation.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

84 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 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 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

Loading scene with LoadSceneAsync freezes and progress jumps from 0% to 90% 2 Answers

How to make functions async? 2 Answers

Multi-threading Alternative 1 Answer

Problem with Coroutines and waitforseconds. 1 Answer

Reset-Cancel Coroutine in Unity 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