I'm developing a poker app i almost have it done and im looking for improvements and 1 of the things i wonder about is should i change my main looping method method ? Currently it's looping by using tail recursive call. However friend of mine suggested me to switch it to a iteration since it's using a while loop and loop's don't require stack space. Here's my code as it is now.
private async Task Turns()
{
_turns = ReturnTurns();
GC.KeepAlive(Updates);
if (!Player.FoldTurn && Player.Chips > 0)
{
if (Player.Turn)
{
SetPlayerStuff(true);
Call -= Player.PreviousCall;
_up = int.MaxValue;
_turnCount++;
Bot1.Turn = true;
_restart = true;
}
}
if (!Player.Turn)
{
await Flip(0);
}
if (Player.FoldTurn || !Player.Turn || Player.Chips <= 0)
{
Call = TempCall;
if (StatusLabels[Player.EnumCasted].Contains(RepetitiveVariables.Fold))
{
Bot1.Turn = true;
}
SetPlayerStuff(false);
Bot1 = (Bot)await RotateTurns(Bot1, Bot1.EnumCasted);
Bot2 = (Bot)await RotateTurns(Bot2, Bot2.EnumCasted);
Bot3 = (Bot)await RotateTurns(Bot3, Bot3.EnumCasted);
Bot4 = (Bot)await RotateTurns(Bot4, Bot4.EnumCasted);
Bot5 = (Bot)await RotateTurns(Bot5, Bot5.EnumCasted);
_restart = false;
}
if (!_restart)
{
await Turns();
}
}
That's how i think it should look's like with a loop:
private async Task Turns()
{
while (true)
{
_turns = ReturnTurns();
GC.KeepAlive(Updates);
if (!Player.FoldTurn && Player.Chips > 0)
{
if (Player.Turn)
{
SetPlayerStuff(true);
Call -= Player.PreviousCall;
_up = int.MaxValue;
_turnCount++;
Bot1.Turn = true;
_restart = true;
}
}
if (!Player.Turn)
{
await Flip(0);
}
if (Player.FoldTurn || !Player.Turn || Player.Chips <= 0)
{
Call = TempCall;
if (StatusLabels[Player.EnumCasted].Contains(RepetitiveVariables.Fold))
{
Bot1.Turn = true;
}
SetPlayerStuff(false);
Bot1 = (Bot) await RotateTurns(Bot1, Bot1.EnumCasted);
Bot2 = (Bot) await RotateTurns(Bot2, Bot2.EnumCasted);
Bot3 = (Bot) await RotateTurns(Bot3, Bot3.EnumCasted);
Bot4 = (Bot) await RotateTurns(Bot4, Bot4.EnumCasted);
Bot5 = (Bot) await RotateTurns(Bot5, Bot5.EnumCasted);
_restart = false;
}
if (!_restart)
{
continue;
}
break;
}
}
Generally, the JIT is not able to replace recursion with a loop. This is a fairly esoteric optimization scenario.
Here, this does not even come into play because an async method uses very different call mechanisms internally.
This code will consume "stack space" proportional to the recursion depth. (It's not necessarily stack space with async methods. Could be heap space in the form of a linked list.)
From a code quality standpoint I find the loop vastly preferable because recursion is not what most people are used to. Here, there really is no algorithmic need for recursion. Seems like the wrong tool for the job. I think you have used recursion as a replacement for "goto" here because all this does is jump back to the beginning of the method.
You can make the jump condition a little cleaner:
if (!_restart) break;
Related
I am developing a plugin for an application.
The application is calling the plugin when it loads and the plugin start and endless look in this form:
const int sleepTime = 60 * 1000;
while (true)
{
try
{
Thread.Sleep(sleepTime);
//vaProxy.WriteToLog("Invoking checker...", "Green");
Dictionary<string, dynamic> SessionState = vaProxy.SessionState;
Dictionary<string, CallBack> callBacks = vaProxy.SessionState["CallBacks"];
//Checks will only occur in the Pit
if (!Config.IsProcessRunning("Falcon BMS")) continue;
var isJoystickProfileLoaded = vaProxy.GetBoolean("isJoystickProfileLoaded");
bool isProfileLoaded = isJoystickProfileLoaded == true;
if (ConfigFile.IsTrue(vaProxy, "EnableJoystickLoaded") &&
!vaProxy.SessionState["JanJanJoystickIsLoaded"] && !isProfileLoaded)
{
Config.SaySomething("Verify Joystick profile is loaded");
}
if (!SharedMem.GetStatus("isFlying")) continue;
if (ConfigFile.GetEntry(vaProxy, "AutoAVTR") == "True" &&
!SharedMem.GetStatus("isOnGround"))
{
//Check AVTR status
if (!SharedMem.GetStatus("AVTR"))
{
callBacks["SimAVTRSwitchOn"]
.Press(vaProxy, sayWhat: "Start recording", waitAfter: 500);
}
}
if (SessionState.ContainsKey("JanJanIsAutoSave") && !SharedMem.GetStatus("isOnGround"))
{
if (vaProxy.SessionState["JanJanIsAutoSave"])
{
//vaProxy.WriteToLog("Checking save time", "Green");
//save game...
GameIO.SaveGame(vaProxy);
}
}
if (!SessionState.ContainsKey("JanJanIsStatusReport")) continue;
if (vaProxy.SessionState["JanJanIsStatusReport"])
{
Sim.MyStatus(vaProxy);
}
}
catch (Exception ex)
{
vaProxy.WriteToLog("Dynamic Checks\n" + ex.Message, "Red");
Console.Beep();
}
}
vaProxy is a dynamic variable controlled by the sending application.
I suspect that this endless loop is causing a memory leak.
How can I prevent this?
Should I use the using() statement and if yes how?
I can convert the "DO SOME STUFF" to a class, will that help?
I was calling a function not created by be which did not dispose of itself properly.
Placing it in a using(){...} block solved it.
I am using a local server/client setup to test a point rendering program I have written. The client receives data points from the server correctly, however due to the high volume of data points that need to be processed, I have used the System.Threading.Tasks library to employ multithreading to process the data faster.
The output of the program should look like this (which currently takes an hour to process):
However, when using my multithreaded solution, it comes out like this:
The code I have used to setup the multithreading is below (initialisation and such is taken care of above the sample).
void Update () {
//Read bytes data from server stream
length = stream.Read(bytes, 0, bytes.Length);
if(length != 0){
// Convert byte array to string message
startedStreaming = true;
finishedStreaming = false;
serverMessage += Encoding.UTF8.GetString(bytes);
}
else{
finishedStreaming = true;
}
if(startedStreaming == true && finishedStreaming == true){
startedStreaming = false;
rendered = false;
readyToProcess = false;
StartCoroutine(DataStreaming());
}
if(readyToRender == true && rendered == false){
rendered = true;
Debug.Log("Rendering");
pcloud.updateBuffer();
}
}
private IEnumerator DataStreaming(){
//Convert bytes data to readable strings once finished receiving
if(finishedStreaming == true && readyToProcess == false){
if(renderer.enabled == false){
renderer.enabled = true;
}
newVectors = serverMessage.Split(new char[]{'\n'} );
Debug.Log("Message split");
pcloud._pointData = new PointCloudData.Point[newVectors.Length];
readyToProcess = true;
}
//Convert strings into numerical values and render once finished
if(readyToProcess == true && readyToRender == false){
readyToRender = true;
Debug.Log("rendering, "+ Time.realtimeSinceStartup);
Parallel.For(0, newVectors.Length, (coord) =>{
row = newVectors[coord].Split(new char[]{','});
float x = int.Parse(row[0]);
float y = int.Parse(row[1]);
float z = int.Parse(row[2]);
pcloud._pointData[coord].position = new Vector3((float)(x/pixelsPerUnit), (float)(y/1000f), (float)(z/pixelsPerUnit));
pcloud._pointData[coord].color = Pcx.PointCloudData.EncodeColor(dict[(int)y]);
});
}
if(readyToRender == true){
yield return new WaitForSeconds(10);
}
}
I am assuming that the mutlithreading is corrupting the data in some way. Is there anything I need to change or fix to get the correct result?
I have implemented a try-catch loop and discovered that a single line of corrupt data was the source of the problem. This appears to be due to the server-socket part of the program and so I won't discuss it further here, but the try-catch loop was a great solution to find where the problem was occurring, and to allow the program to continue despite errors occurring.
The description of the Task.WhenAny method says, that it will return the first task finished, even if it's faulted. Is there a way to change this behavior, so it would return first successful task?
Something like this should do it (may need some tweaks - haven't tested):
private static async Task<Task> WaitForAnyNonFaultedTaskAsync(IEnumerable<Task> tasks)
{
IList<Task> customTasks = tasks.ToList();
Task completedTask;
do
{
completedTask = await Task.WhenAny(customTasks);
customTasks.Remove(completedTask);
} while (completedTask.IsFaulted && customTasks.Count > 0);
return completedTask.IsFaulted?null:completedTask;
}
First off, from my review there is no direct way of doing this without waiting for all the tasks to complete then find the first one that ran successfully.
To start with I am not sure of the edge cases that will cause issues that I havent tested, and given the source code around tasks and contiunuation requires more than an hour of review I would like to start to think around the follow source code. Please review my thoughts at the bottom.
public static class TaskExtensions
{
public static async Task<Task> WhenFirst(params Task[] tasks)
{
if (tasks == null)
{
throw new ArgumentNullException(nameof(tasks), "Must be supplied");
}
else if (tasks.Length == 0)
{
throw new ArgumentException("Must supply at least one task", nameof(tasks));
}
int finishedTaskIndex = -1;
for (int i = 0, j = tasks.Length; i < j; i++)
{
var task = tasks[i];
if (task == null)
throw new ArgumentException($"Task at index {i} is null.", nameof(tasks));
if (finishedTaskIndex == -1 && task.IsCompleted && task.Status == TaskStatus.RanToCompletion)
{
finishedTaskIndex = i;
}
}
if (finishedTaskIndex == -1)
{
var promise = new TaskAwaitPromise(tasks.ToList());
for (int i = 0, j = tasks.Length; i < j; i++)
{
if (finishedTaskIndex == -1)
{
var taskId = i;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
//we dont want to await these tasks as we want to signal the first awaited task completed.
tasks[i].ContinueWith((t) =>
{
if (t.Status == TaskStatus.RanToCompletion)
{
if (finishedTaskIndex == -1)
{
finishedTaskIndex = taskId;
promise.InvokeCompleted(taskId);
}
}
else
promise.InvokeFailed();
});
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
}
return await promise.WaitCompleted();
}
return Task.FromResult(finishedTaskIndex > -1 ? tasks[finishedTaskIndex] : null);
}
class TaskAwaitPromise
{
IList<Task> _tasks;
int _taskId = -1;
int _taskCount = 0;
int _failedCount = 0;
public TaskAwaitPromise(IList<Task> tasks)
{
_tasks = tasks;
_taskCount = tasks.Count;
GC.KeepAlive(_tasks);
}
public void InvokeFailed()
{
_failedCount++;
}
public void InvokeCompleted(int taskId)
{
if (_taskId < 0)
{
_taskId = taskId;
}
}
public async Task<Task> WaitCompleted()
{
await Task.Delay(0);
while (_taskId < 0 && _taskCount != _failedCount)
{
}
return _taskId > 0 ? _tasks[_taskId] : null;
}
}
}
The code is lengthy I understand and may have lots of issues, however the concept is you need to execute all the tasks in parallel and find the first resulting task that completed successfully.
If we consider that we need to make a continuation block of all the tasks and be able to return out of the continuation block back to the original caller. My main concern (other than the fact I cant remove the continuation) is the while() loop in the code. Probably best to add some sort of CancellationToken and/or Timeout to ensure we dont deadlock while waiting for a completed task. In this case if zero tasks complete we never finish this block.
Edit
I did change the code slightly to signal the promise for a failure so we can handle a failed task. Still not happy with the code but its a start.
As part of my school project I'm trying to link two tables to decrease the amount of data stored in one table so I wanted to link my "Scores" class with my "CorrectAnswers" class via the ObjectID. However since the tasks are asynchronous, by the time one task is done saving, the other task has already begun or also finished saving and so the ObjectID returns as null.
Here's the code I'm using:
public void SaveScore()
{
ParseObject SendScore = new ParseObject("Scores");
SendScore["Score"] = CheckAnswer.score;
SendScore["user"] = ParseObject.CreateWithoutData("_User", ParseUser.CurrentUser.ObjectId);
SendScore["TestMode"] = MainMenu.testmode;
SendScore["TotalQuestions"] = QuestionCreation.TotalQuestions;
SendScore["CorrectQuestions"] = CheckAnswer.CorrectQuestions;
SendScore.SaveAsync().ContinueWith(t =>
{
ScoreObjectId = SendScore.ObjectId;
});
ParseObject SendCorrectTopics = new ParseObject("CorrectAnswers");
SendCorrectTopics["Score"] = SendScore.ObjectId;
for (int i = 0; i <= 9; i++)
{
string Topic = "Topic" + (i + 1).ToString();
SendCorrectTopics[Topic] = CheckAnswer.CorrectTopics[i];
}
SendCorrectTopics.SaveAsync();
SceneManager.LoadScene(0);
}
How would I be able to make the second save hold until the first save has finished? I'm somewhat new to C# and so don't quite know all it's features yet. I've looked into "await" but unity doesn't seem to like that. Any help would be greatly appreciated!
Thanks in advance,
EDIT: Okay, after a bit more reading on Unity's coroutines, I found a much better way of checking that only relies on checking when needed:
IEnumerator CheckSave()
{
while(ScoreObjectId == null & !DoneSave))
{
print("Running");
yield return new WaitForSeconds(0.5f);
}
DoneSave = false;
SaveTotalTopics();
}
This seems like a much better way of doing it.
Well, it seems the answer was something I've already done before, even if it is a little ugly.
Using Unity's update function I created a check to make sure the ObjectID is not null and the previous save had completed, as so:
void Update () {
if (ScoreObjectId != null & DoneSave)
{
DoneSave = false;
SaveTotalTopics();
}
Thus splitting it into two saves and creating:
public void SaveScore()
{
ParseObject SendScore = new ParseObject("Scores");
SendScore["Score"] = CheckAnswer.score;
SendScore["user"] = ParseObject.CreateWithoutData("_User", ParseUser.CurrentUser.ObjectId);
SendScore["TestMode"] = MainMenu.testmode;
SendScore["TotalQuestions"] = QuestionCreation.TotalQuestions;
SendScore["CorrectQuestions"] = CheckAnswer.CorrectQuestions;
Task SendingScores = SendScore.SaveAsync().ContinueWith(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
DoneSave = false;
print(t.Exception);
}
else
{
DoneSave = true;
print("Setting object ID!");
ScoreObjectId = SendScore.ObjectId;
print(ScoreObjectId);
}
});
}
void SaveTotalTopics()
{
for (int i = 0; i <= 9; i++)
{
string Topic = "Topic" + (i + 1).ToString();
SendCorrectTopics[Topic] = CheckAnswer.CorrectTopics[i];
}
SendCorrectTopics["UserScore"] = ParseObject.CreateWithoutData("Scores", ScoreObjectId);
SendCorrectTopics.SaveAsync().ContinueWith(t =>
{
if(t.IsFaulted || t.IsCanceled)
{
print(t.Exception);
}
else
{
print("Saved!");
}
});
}
I'd also forgotten to use ParseObject.CreateWithoutData() so my first code snippet wouldn't have worked even if I'd found a better method...
So, although I'm not happy with the final result, at least it works and I don't think running an if statement every frame should significantly impact on my game's performance.
Why not use a bool and a while loop?
public IEnumerator SaveScore()
{
bool canContinue = false;
ParseObject SendScore = new ParseObject("Scores");
SendScore["Score"] = CheckAnswer.score;
SendScore["user"] = ParseObject.CreateWithoutData("_User", ParseUser.CurrentUser.ObjectId);
SendScore["TestMode"] = MainMenu.testmode;
SendScore["TotalQuestions"] = QuestionCreation.TotalQuestions;
SendScore["CorrectQuestions"] = CheckAnswer.CorrectQuestions;
SendScore.SaveAsync().ContinueWith(t =>
{
ScoreObjectId = SendScore.ObjectId;
//set the bool canContinue to true because the first portion of code has finished running
canContinue = true;
});
//wait while the canContinue bool is false
while(!canContinue){
yield return null;
}
//continue your parse code
ParseObject SendCorrectTopics = new ParseObject("CorrectAnswers");
SendCorrectTopics["Score"] = SendScore.ObjectId;
for (int i = 0; i <= 9; i++)
{
string Topic = "Topic" + (i + 1).ToString();
SendCorrectTopics[Topic] = CheckAnswer.CorrectTopics[i];
}
SendCorrectTopics.SaveAsync();
SceneManager.LoadScene(0);
return null;
}
I have a list of string and if I run spell checking using NHunspell in sequential manner then everything works fine; but if I use Parallel.For loop against the List the application stops working in the middle( some address violation error )
public static bool IsSpellingRight(string inputword, byte[] frDic, byte[] frAff, byte[] enDic, byte[] enAff)
{
if (inputword.Length != 0)
{
bool correct;
if (IsEnglish(inputword))
{
using (var hunspell = new Hunspell(enAff, enDic))
{
correct = hunspell.Spell(inputword);
}
}
else
{
using (var hunspell = new Hunspell(frAff, frDic))
{
correct = hunspell.Spell(inputword);
}
}
return correct ;
}
return false;
}
Edit:
var tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
var poptions = new ParallelOptions();
// Keep one core/CPU free...
poptions.MaxDegreeOfParallelism = Environment.ProcessorCount - 1;
Task task = Task.Factory.StartNew(delegate
{
Parallel.For(0, total, poptions, i =>
{
if (words[i] != "")
{
_totalWords++;
if (IsSpellingRight(words[i],dictFileBytes,
affFileBytes,dictFileBytesE,affFileBytesE))
{
// do something
}
else
{
BeginInvoke((Action) (() =>
{
//do something on UI thread
}));
}
}
});
}, tokenSource.Token);
task.ContinueWith((t) => BeginInvoke((Action) (() =>
{
MessaageBox.Show("Done");
})));
I think you should forget about your parallel loop implement the things right.
Are you aware of the fact that this code loads and constructs the dictionary:
using (var hunspell = new Hunspell(enAff, enDic))
{
correct = hunspell.Spell(inputword);
}
Your are loading and construction the dictionary over and over again with your code. This is awfully slow! Load Your dictionary once and check all words, then dispose it. And don't do this in parallel because Hunspell objects are not thread safe.
Pseodocode:
Hunspell hunspell = null;
try
{
hunspell = new Hunspell(enAff, enDic)
for( ... )
{
hunspell.Spell(inputword[i]);
}
}
}
finally
{
if( hunspell != null ) hunspell.Dispose();
}
If you need to check words massive in parallel consider to read this article:
http://www.codeproject.com/Articles/43769/Spell-Check-Hyphenation-and-Thesaurus-for-NET-with
Ok, now I can see a potential problem. In line
_totalWords++;
you're incrementing a value, that (I suppose) is declared somewhere outside the loop. Use locking mechanism.
edit:
Also, you could use Interlocked.Increment(ref val);, which would be faster, than simple locking.
edit2:
Here's how the locking I described in comment should look like for the problem you encounter:
static object Locker = new object(); //anywhere in the class
//then in your method
if (inputword.Length != 0)
{
bool correct;
bool isEnglish;
lock(Locker) {isEnglish = IsEnglish(inputword);}
if(isEnglish)
{
//..do your stuff
}
//rest of your function
}