Coroutine to run SQL in Unity3d - c#

I'm trying to understand Unity coroutines deeper. They can block execution yielding null or wait, but they are really not new threads.
In my case Unity should read info from database, which can take some time. And this is synchronous operation. This single line of code may potentially block execution for seconds.
Part of me tells just to start new thread. But I'm wondering whether it can be achieved with Unity-style coroutines.
private IEnumerator FetchPlayerInfo(int id)
{
// fetch player from DB
using (var session...)
{
// this line is NHibernate SQL query, may take long time
player = session.QueryOver<Player>()...;
}
// raise event to notify listeners that player info is fetched
}
I just don't see where to put yield. Does anyone know?
Thx in advance.

You can only return yield instructions when the control flow is in your own coroutine. If you have to run a long synchronous operation, and it has no asynchronous API (which is something to be expected from a database), then you really better off with starting another thread.
However, be aware that using other threads in Unity is a little bit tricky: you won't be able to use any of Unity's API and you'll have to check in the main thread for when the worker thread has a result ready. Consider looking at ready solutions, such as Loom.

You can think of yielding as breaking a large task into chunks. After each chunk you yield to let other things happen, then come back and do another chuck. In your case you would load X number of rows each chunk until all your data is loaded.

Related

Unity: Offloading decision making to threads for efficiency?

I've got a fairly large Unity application here that has a lot of concurrent things happening at once. I realized that having all my evaluation, iteration, enumeration, decision making, and arithmetic logic being done in or called from Update() is starting to have a performance impact. I've since then offloaded most of this logic to Coroutines, and that has gained back some performance, but I'm trying to think of what I can do to make this better.
Coroutines have gained back performance when iterating over some large collection because I can yield at the end of each loop, but in some cases where it's a massive collection, processing one item each frame makes this task considerably slow. This is where I'm instead starting to offload these sorts of tasks to Threads. Problem with using Threads in Unity is that it tends to throw a fit if you call the Unity API from the Thread. So to combat that, I came up with this design pattern where the non-Unity logic is done in a thread, then once a decision or result was made, some additional Unity-required logic based on context is done in Unity's main thread.
public class Evaluator : MonoBehaviour {
public static Evaluator Instance;
static Queue<Func<Action>> evaluationQueue = new Queue<Func<Action>>();
static Queue<Action> actionQueue = new Queue<Action>();
static Thread evaluatorLoop;
public static void EvalLogic (Func<Action> evaluation) {
if (Instance == null) {
NanoDebug.LogError("EVALUATOR IS NOT INITIALIZED!");
return;
}
evaluationQueue.Enqueue(evaluation);
if (evaluatorLoop == null) {
evaluatorLoop = new Thread(EvaluatorLoop);
evaluatorLoop.IsBackground = true;
evaluatorLoop.Start();
}
}
static void EvaluatorLoop () {
for (;;) {
if (evaluationQueue.Count > 0) {
Func<Action> evaluation = evaluationQueue.Dequeue();
Action action = evaluation();
actionQueue.Enqueue(action);
}
else {
break;
}
}
evaluatorLoop = null;
}
void Awake () {
Instance = this;
}
void FixedUpdate () {
if (actionQueue.Count > 0) {
actionQueue.Dequeue()?.Invoke();
}
}
}
In some regular script, I would use this like so
void OnSomeGameEvent (GameEventBigData bigData) {
Func<Action> checkData = () => {
// Iterate over some big collection.
// Do X if some condition is met during iteration.
// Do some arithmetic with data.
// Evaluate some large if-statement or switch statement.
// Return this Action based on the decision or result of the above.
return () => {
// Mutate the state of some object involving the Unity API using evaluated data.
};
};
Evaluator.EvalLogic(checkData);
}
I've ran into a simular problem with large iterations using this pattern. While the Thread does the iteration also instantly, if I need to mutate the state of a collection of Game Objects (each one), then the above action queue fills up to the size of the collection and then it's up to the speed of FixedUpdate() to apply the selected changes. But, when it comes to complex decision making or doing math, this pattern seems to help Unity not skip a beat.
So my question is: Am I really gaining performace this way, or am I better off sticking to just Coroutines and intelligently yielding when necessary?
Here's my understanding of what Update() is. It's a render loop, right? If you want to chagne the state of a Game Object in such a way that it changes the visual appearance or location, you do it Update(). That being said, doesn't it make more sense to then offload ALL non-render related tasks from Update()?
tl;dr: Depends on your specific use case.
Am I really gaining performace this way, or am I better off sticking to just Coroutines and intelligently yielding when necessary?
That totally depends on what actually is done by the threads / Coroutine and how many of them you are using etc.
Using threads for performance instense things (mostly FileIO, parsing operations on large or many strings or in general large data processing) wherever you can definitely is a performance gain. However, have in mind that also creating threads has a certain overload. If you are to create them on a regular basis it is even better to have one persistent thread and then pass in work packages it has to solve. While there are no packages it should then sleep for a certain amount of time (e.g. 17ms which is about a frame in 60 FpS or even longer - I e.g. usually used 50ms and for now was quite happy with the results) so it doesn't eat up 100% of CPU time while it has nothing to do.
It's a render loop, right?
Not really, no. Update is just a message that gets invoked once each frame. What you do in there is of course up to you. As yourself said most of the Unity API (namely these parts that directly affect the scene or assets or rely on them) can only be used within the Unity main thread, so any of Unity's built-in messages (Update, FixedUpdate, etc).
That being said, doesn't it make more sense to then offload ALL non-render related tasks from Update()?
No! That would be overdoing it a little. Heavy things, yes why not. But have in mind that your device only has a limited amount of parallel CPU cores to work off all the Threads and Tasks. At a certain point the overhead just grows bigger than the actual work that is done. I wouldn't move each and any Vector3 calculation into a thread / workPackage .. but if you have to do 1000 of them, again, sur why not.
So as said basically it all comes down to: Depends on your specific use case.
Alternatively to Threads depending on your needs you might also want to look into the Unity Job System and the Burst Compiler which enables to do a lot of things asynchronous that are usually somehow bound to the Unity main thread.
In particular it is used a lot in combination with the new Mesh API.
And yet another alternative for heavy but generic mathematical operations would be using Compute Shaders so handing all the work to the GPU. This stuff can get extremly complex but at the same time extremly fast and powerfull. (Again see the examples and times in the MeshAPI examples)
And in general yes, this kind of dispatching actions/results back into the main thread is the typical solution. Just make sure to either lock your actionQueue or rater use a ConcurrentQueue to not get into threading issues.
Additionally you can have a Coroutine for working the packages off that skips to the next frame if too much time has passed already so you can still achieve a certain target framerate. You could achieve this e.g. using a StopWatch. This requires of course to implement certain points where it may skip (yield) like for example after each worked package / Action.
const float targetFrameRate = 60;
// yes, if you make Start return IEnumerator then Unity automatically
// runs it as a Coroutine
private IEnumerator Start()
{
// -> about 17 -> actual frame-rate might be only 58 or lower
var maxMS = Mathf.RoundToInt(1000f / targetFrameRate);
var stopWatch = new StopWatch();
stopWatch.Start();
// This is ok in a Coroutine as long as you yield inside
// in order to at least render one frame eventually
while(true)
{
if (actionQueue.Count > 0)
{
actionQueue.Dequeue()?.Invoke();
// after each invoked action check if the time has already passed
if(stopWatch.ElapsedMilliseconds >= targetFrameRate)
{
// render this frame and continue int he next
yield return null;
// and restart the timer
stopWatch.Restart();
}
}
else
{
// Otherwise directly go to the next frame
yield return null;
// and restart the timer
stopWatch.Restart();
}
}
}
If this still is not enough and your Action itself is too intensive you could split it up in multiple Actions in order to again allow to skip between them. Like e.g. instead of doing
Enqueue(LoopThroughObjectsAndDoStuff(thousendObjects));
you would rather do
foreach(var x in thousendObjects)
{
Enqueue(()=>DoStuffForObject(x));
}
Have in mind though that there is tradeoff and you have to play around a bit with the target frame-rate and the real-time until everythign is done.
There are situations where you prefer that a User has to wait effectively longer until something is finished but meanwhile have the application run with a good frame-rate. And there are other situations where you allow that the app runs with a lower frame-rate or even little freezes but the process is finished effectively faster.

Tell if Concurrent Queue updated without looping

thanks for the assistance. I've got a triple-threaded process, linked by a concurrent queue. Thread one processes information, returns to the second thread, which places data into a concurrent queue. The third thread is just looping like so:
while (true) {
if(queue.TryDequeue(out info)) {
doStuff(info);
} else {
Thread.Sleep(1);
}
}
Is there a better way to handle it such that I'm not iterating over the loop so much? The application is extremely performance sensitive, and currently just the TryDequeue is taking ~8-9% of the application runtime. Looking to decrease that as much as possible, but not really sure what my options are.
You should consider using System.Collections.Concurrent.BlockingCollection and its Add() / Take() methods. With Take() your third thread will be just suspended while waiting for new item. Add() is thread safe and can be used by second thread.
With that approach you should be able to simplify your code into something like that:
while (true) {
var info = collection.Take();
doStuff(info);
}
You can increase the sleep time. I would also use await Task.Delay instead of sleep. This way you can wait longer without the extra cpu cycles that Thread.Sleep uses and still be able to cancel the delay by making use of the CancellationTokenSource.
On another note, there are better ways of queuing up jobs. Taking into consideration that it appears you want to run these jobs synchronously, an example would be to have a singleton class that takes your work items and queues them up. So if there are no items in the queue when you add one, it should detect that and then start your job process. At the end of your job process, check for more work, use recursion to do that work or if no more jobs then exit the job process, which will run again when you add an item to the empty queue. If my assumption is wrong and you can run these jobs in parallel, why use a queue?
You may like to use a thread safe implementation of ObservableCollection. Check out this SO question ObservableCollection and threading
I don't have a recommendation that avoids looping, however I would recommend you move away from
while (true)
and consider this instead:
MyThing thing;
while (queue.TryDequeue(out thing))
{
doWork(thing);
}
Put this in a method that gets called each time the queue is modified, this ensures it is running when needed, but ends when not needed.

Writing to a file asynchronously, but in order

I've got some code which saves data from an object to XML. This locked the UI for a few seconds so I made it so it wouldn't.
foreach (Path path in m_canvasCompact.Children)
{
Task.Run(() => WritePathDataToXML(false, path));
}
Private void WritePAthDataToXML(bool is32x32, Path path)
{
//stuff going on...
xmlDoc.Root.Descendants.......Add(iconToAdd);
xmlDoc.Save(..);
}
The problem is (as expected) the order in which the data is written to the XML is in a random order depending upon the speed in which the tasks finish (I assume)
I could probably write some bodged code which looks at the XML and rearranges it once everything has been completed, but that's not ideal. Is there anyway to do this on a separate thread, but perhaps only one at a time, so they get executed and saved in the correct order.
Thanks.
It sounds like you want a producer/consumer queue. You can rig that up fairly easily using BlockingCollection<T>.
Create the blocking collection
Start a task which will read from the collection until it's "finished" (simplest with GetConsumingEnumerable), writing to the file
Add all the relevant items to the collection - making sure you do everything that touches UI elements within the UI thread.
Tell the collection it's "finished" (CompleteAdding)
Alternatively, as suggested in comments:
In the UI thread, create a collection with all the information you need from UI elements - basically you don't want to touch the UI elements within a non-UI thread.
Start a task to write that collection to disk; optionally await that task (which won't block the UI)
That's simpler, but it does mean building up the whole collection in memory before you start writing. With the first approach, you can add to the collection as you write - although it's entirely possible that if building the collection is much faster than writing to disk, you'll end up with the whole thing in memory anyway. If this is infeasible, you'll need some way of adding "gently" from the UI thread, without blocking it. It would be nice if BlockingCollection had an AddAsync method, but I can't see one.
We don't know enough about what you're doing with the Path elements to give you sample code for this, but hopefully that's enough of a starting point.
Run the whole loop in a Task:
Task.Run(()=>{
foreach (Path path in m_canvasCompact.Children)
{
WritePathDataToXML(false, path);
}
});
This will still take the same time, but should not block the UI.

multithread read and process large text files

I have 10 lists of over 100Mb each with emails and I wanna process them using multithreads as fast as possible and without loading them into memory (something like reading line by line or reading small blocks)
I have created a function which is removing invalid ones based on a regex and another one which is organizing them based on each domain to other lists.
I managed to do it using one thread with:
while (reader.Peek() != -1)
but it takes too damn long.
How can I use multithreads (around 100 - 200) and maybe a backgroundworker or something to be able to use the form while processing the lists in parallel?
I'm new to csharp :P
Unless the data is on multiple physical discs, chances are that any more than a few threads will slow down, rather than speed up, the process.
What'll happen is that rather than reading consecutive data (pretty fast), you'll end up seeking to one place to read data for one thread, then seeking to somewhere else to read data for another thread, and so on. Seeking is relatively slow, so it ends up slower -- often quite a lot slower.
About the best you can do is dedicate one thread to reading data from each physical disc, then another to process the data -- but unless your processing is quite complex, or you have a lot of fast hard drives, one thread for processing may be entirely adequate.
There are multiple approaches to it:
1.) You can create threads explicitly like Thread t = new Thread(), but this approach is expensive on creating and managing a thread.
2.) You can use .net ThreadPool and pass your executing function's address to QueueUserWorkItem static method of ThreadPool Class. This approach needs some manual code management and synchronization primitives.
3.) You can create an array of System.Threading.Tasks.Task each processing a list which are executed parallely using all your available processors on the machine and pass that array to task.WaitAll(Task[]) to wait for their completion. This approach is related to Task Parallelism and you can find detailed information on MSDN
Task[] tasks = null;
for(int i = 0 ; i < 10; i++)
{
//automatically create an async task and execute it using ThreadPool's thread
tasks[i] = Task.StartNew([address of function/lambda expression]);
}
try
{
//Wait for all task to complete
Task.WaitAll(tasks);
}
catch (AggregateException ae)
{
//handle aggregate exception here
//it will be raised if one or more task throws exception and all the exceptions from defaulting task get accumulated in this exception object
}
//continue your processing further
You will want to take a look at the Task Parallel Library (TPL).
This library is made for parallel work, in fact. It will perform your action on the Threadpool in whatever is the most efficient fashion (typically). The only thing that I would caution is that if you run 100-200 threads at one time, then you possibly run into having to deal with context switching. That is, unless you have 100-200 processors. A good rule of thumb is to only run as many tasks in parallel as you have processors.
Some other good resources to review how to use the TPL:
Why and how to use the TPL
How to start a task.
I would be inclined to use parallel linq (plinq).
Something along the lines of:
Lists.AsParallel()
.SelectMany(list => list)
.Where(MyItemFileringFunction)
.GroupBy(DomainExtractionFunction)
AsParallel tells linq it can do this in parallel (which will mean the ordering of everything following will not be maintained)
SelectMany takes your individual lists and unrolls them such that all all items from all lists are effectivly in a single Enumerable
Where filers the items using your predicate function
GroupBy collects them by key, where DomainExtractionFunction is a function which gets a key (the domain name in your case) from the items (ie, the email)

how to implement a step-by-step button in c#?

I implemented an algorithm in c# and I want to make a gui for it, in my gui i want to put a button that with any click the gui shows a step forward in algorithm, so i think i need to put something like pause? statements in my code that with any click it can resume. how should i do that? or is there any other suggestion for implementing this idea?
It sounds like really you need to turn your algorithm into a state machine - instead of actively "pausing" it, you would actively "advance" it.
You may find iterator blocks useful... if your algorithm is pretty much in one method at the moment, you may be able to change it to insert a yield return statement at the end of each logical step, returning some indication of the current status.
That's not an entirely normal use of iterator blocks, but it could be the simplest way forward here. Your UI would call GetEnumerator once at the start, and then MoveNext() each time the button is clicked (followed by accessing the Current property to get at the current state). Don't forget to dispose of the iterator when you've finished with it.
Run your algorithm in a thread different than your UI thread.
For synchronization, create some kind of wait handle, e.g. an AutoResetEvent.
The "pause" statement you are looking for is myWaitHandle.WaitOne() (called by your algorithm thread).
Allow the algorithm to continue by executing myWaitHandle.Set() in your UI thread.
This method has the advantage that your user interface stays responsive while a step of your algorithm is being executed.
You have to decide what is a "step" in your algorithm. Then you need to rewrite your algorithm and wrap it in a class with the following interface:
interface ISteppedAlgorithm
{
bool NextStep(); //returns if the algorithm is finished
IStepResult LastStepResult {get;}
}
and now your GUI will drive the algorithm prepared in this way. After you press the button, the NextStep() method will be invoked. If it returns false disable the button (or indicate in whatever other way that its all done). Then read the LastStepResults and update the display.h
From your description I think you want a "wizard" that is basically an application with previous / next buttons.
http://www.differentpla.net/content/2005/02/implementing-wizard-c
However If you just have a long running task and want to have some breaks in it, there are different ways to solve it.
Sperate you task in multiple methods.
After a method is completed, wait until the user hit's next.
Let the task run in it's own thread and at a point where it should wait let the thread sleep until you set a specific var:
LongRunningMethod1();
while(continue1 == true)
{
Thread.Sleep(50);
}
LongRunningMethod2()
while(continue2 == true)
{
Thread.Sleep(50);
}
Set continue1 and 2 to true in your main thread to let the background thread do his work.
If it's just to "observe" the state of the algorithm as it develops, why not add some events (probably just one at the end) and let the event handler store an array of the states. The UI can simply iterate forward\backwards over this as and when needed.

Categories

Resources