Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Friday, 14 November 2014

PTaskScheduler - A Free and .Net pure parallel task scheduler

For Android, iOS, Windows Phone, Windows, MacOS, Linux and probably a whole set of other platforms that support .Net natively. Try it, it's free!

If you are new to UniParallel, please read the post Using PTaskScheduler - UniParallel Unity package first.


Version 0.6 of the UniParallel package adds a new type of task scheduler called  PSyncTaskScheduler  which has the same functionalities of the  PTaskScheduler  adding to it the ability to execute a routine in the main game Thread after a task is finished.
Only 3 of types of tasks are supported, named slightly different:

  • Use SyncImmediateTask if you want to schedule a task for immediate execution
  • Use SyncTimedTask if you want to schedule a task for delayed execution
  • Use SyncRepeatableTask to execute tasks a certain number of times on a interval

Infinite synchronized tasks are supported, obviously, since the purpose of the sync tasks is to execute another routine when finished.

And every starts with and instance of  PSyncTaskScheduler 

If you are looking for the Unity Version, get free at the Unity Asset Store


The .Net Library works on anything that can run .Net (including Mono and variations). Download the library free HERE



 [...]
 PSyncTaskScheduler scheduler = new PSyncTaskScheduler();
 // schedule your tasks
 [...]
 // check if there's any tasks finished and execute it's post completion routine
 scheduler.Update(); 

The line
scheduler.Update();
Is extremely important and must be included in your MonoBehaviour update loop. This call is responsible for executing and post-completion routine scheduled. That is, if there's any completed tasks. Calling PSyncTaskScheduler.Update() when there are no tasks completed or scheduled is completely safe and will cause no impact on your application performance whatsoever.
Let's see an example of a immediate task that will execute a heavy operation in the background and notify the game when completed
 
 [...]
 PSyncTaskScheduler scheduler = new PSyncTaskScheduler();
 SyncImmediateTask task = new SyncImmediateTask(MethodThatCanBlockMyGame, MethodToRunAfterBlockingMethodIsDone);
 scheduler.Enqueue(task);
 [...]

 // The MonoBehaviour update loop
 void Upate()
 {
    scheduler.Update()
 }
 object MethodThatCanBlockMyGame()
 {
    // this is running in the background and allowing your game to continue smoothly
    Boolean isDone = true;
    // Do a few very heavy operations
    ThisIsGoingToTakeALongTime();
    // isDone is the argument passed to MethodToRunAfterBlockingMethodIsDone
    return isDone;
 }
 
 void MethodToRunAfterBlockingMethodIsDone(object result)
 {
   // this is running inside the game's main thread and MUST BE very light-weight code
   Boolean booleanResult = (Boolean) result;  // result is coming from  MethodThatCanBlockMyGame
   if(result)
   {
     Debug.Log("Completed successfully");
   }
   else
   {
     Debug.Log("Ooops");
   }
 }

Note the signatures of the methods  MethodThatCanBlockMyGame  and  MethodToRunAfterBlockingMethodIsDone : they *must* work with only object types, the background method returning and object that will be passed as an argument to the method executed after the background routine is completed.
Let's take a look at the other 2 types of synchronized tasks. They are just as simple to use as immediate tasks. First, timed tasks
 
 [...]
 const int delay = 1000; // 1 second
 PSyncTaskScheduler scheduler = new PSyncTaskScheduler();
 SyncTimedTask timedTask = new SyncTimedTask(MethodToStartAfterDelay, MethodToExecuteAfterComplete, delay); 
 scheduler.Enqueue(timedTask);
 [...]

 // The MonoBehaviour update loop
 void Upate()
 {
    scheduler.Update()
 }
 object MethodToStartAfterDelay()
 {
    // this is running in the background, starting after the specified delay
    Integer calculationResult = DoSomeMath();
    return calculationResult;
 }
 
 void MethodToExecuteAfterComplete(object result)
 {   
   Debug.Log("The calculated number is "+result);   
 }

Then, SyncRepeatableTask tasks. This time of task is not only useful for executing heavy operations in background but also delayed repeatable operations that will result in something to be rendered, like a countdown timer
 
 [...]

 const int delay = 1000;// run every second ...
 const int executionCount = 10; // and 10 times
 
 int mInitialTimerValue = 10;

 PSyncTaskScheduler scheduler = new PSyncTaskScheduler();
 //count down 10 seconds
 SyncRepeatableTask repeatableTask = new SyncRepeatableTask(CountDown, OnEachCountDown, 
                delay, executionCount);
 scheduler.Enqueue(repeatableTask);

 // The MonoBehaviour update loop
 void Upate()
 {
    scheduler.Update()
 }
 
 object CountDown()
 {
    mInitialTimerValue--;
    return mInitialTimerValue;
 }
 
 void OnEachCountDown(object result)
 {   
   Debug.Log("The timer now is at "+result);   
   RenderTimer(mInitialTimerValue);
 }

Wednesday, 12 November 2014

How to parse and read large (or small) XML files in .Net using C#

Frequently I hear people saying the XML is going to die soon and be full replaced by JSON. That may even happen one day but the truth is there's plenty of XML data around that needs to be processed.

The .Net framework offers many ways to parse and process XML files, some more convenient than others but I find that they can be problematic when parse extremely large amounts of data.

The example below demonstrates how you can quickly use the XmlTextReader class to read the contents of an XML file being modest on memory utilization

Assume you have an xml file like this:

<albums>
  <album releasedate="February 15, 1975">Fly by Night</album>
  <album releasedate="September 1, 1977">A Farewell to Kings</album>
  <album releasedate="June 12, 2012">Clockwork Angels</album>
</albums>


And want to extract all the album names in it. You can do it like this:

// this is just a outer method used to keep things clean.
// note the finally block closing the XML reader resources
// it will return a list of all album names in the XML file above, in their appearing order
private IList< String > GetAlbumNames(String albumXmlFileName)
{            
    // creates a xmlReader to parse the file in albumXmlFileName
    XmlTextReader xmlReader = new XmlTextReader(albumXmlFileName);
    try{
        return GetAlbumNames(xmlReader);
    }
    finally
    {
        xmlReader.Close();
    }                        
}

private IList< String > GetAlbumNames(XmlTextReader xmlReader)
{
    IList< String > albumNames = new List< String >();
            
    // keeps moving the "cursor" in the file till the end
    while (xmlReader.Read())
    {
        // regular nodes are typically a XML Element of type XmlNodeType.Element and the Name property
        // of the node
        if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "album")
        {                  
            // at this exact point, the cursor is pointing to the Element node
            // we need to do another read to move the cursor to the content of the node we want to read  
            xmlReader.Read();
            string albumName = xmlReader.Value;
            albumNames.Add(albumName);
        }

    }
    return albumNames ;
}



If you want to read an attribute present in one of the nodes, e.g, "releaseDate" in your example XML above, you can just the method GetAttribute
Like this:
private IList< String > GetAlbumReleaseDates(XmlTextReader xmlReader)
{
    IList< String > albumReleaseDates = new List< String >();
            
    while (xmlReader.Read())
    {
        // the attribute releaseData belongs to the element album so we need to make sure
        // the cursor is in the right place
        if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "album")
        {                  
            String releaseDate = xmlReader.GetAttribute("releaseDate");
            // always check for nulls, even if you're enforcing schema to have attributes. It is a good practice
            if(releaseDate != null)
            {
              albumReleaseDates.Add(releaseDate);
            }
        }
    }
    return albumReleaseDates ;
}


For more on XmlTextReader, see this. As I mentioned before, there plenty of other alternatives to parse XML in .Net and I shall write about them in my next posts.

Monday, 3 November 2014

How to use the .Net ThreadPool

As many of you have requested, here are a few simple ways you can execute code in a thread using the .Net native ThreadPool.
It works on Windows, Unity (Mono, Android, iOS, Windows Phone)

The simplest case first: Executing a method disregarding the argument
private void SimpleThreadPoolTest()
{
  ThreadPool.QueueUserWorkItem(new WaitCallback(SimpleMethod));
}  

private void SimpleMethod(object ignoredArg)
{
  Console.WriteLine("Method called inside a thread");
}


As you may have noticed, the WaitCallback delegate takes one argument of type object, which we're ignoring right now.
But if you need to use, just pass any object as the second argument of QueueUserWorkItem, like:
private void ParameterizedThreadPoolTest()
{
  string arg = "This is a string parameter";
  ThreadPool.QueueUserWorkItem(new WaitCallback(SimpleMethod), arg);
}  

private void WaitCallback(object arg)
{
  Console.WriteLine("Executing inside a thread with argument "+arg);
}


You can also use lambda expressions instead of methods
private void LambdaThreadPoolTest()
{
  // unusedArgument is required, even though we're not using it, because WaitCallback takes 1 argument
  ThreadPool.QueueUserWorkItem(new WaitCallback(
        (unusedArgument)=>
        {
          // do something
          // then do something else
          Console.WriteLine("This is a lambda function running inside a thread");
        }
  ));
}  

Wednesday, 29 October 2014

How to download files asynchronously using only HTTP

all you need is these 2 simple methods in your class.
private void downloadFile(string fileUrl)
{ 
  HttpWebRequest request;
 
  request = WebRequest.Create(fileUrl) as HttpWebRequest;
  // this reduces connection time considerably but it's not supported in windows phone 8
  request.Proxy = null; 
 
  if(request != null)
  {
    request.BeginGetResponse(downloadFile, request); 
  }
}
 
private void downloadFile(IAsyncResult responseResult)
{   
  HttpWebRequest request = responseResult.AsyncState as HttpWebRequest ;
  if(request != null)
  {
    // the using here is VERY important if you don't want leaks
    using (WebResponse response = request.EndGetResponse(responseResult))
    {
      if(((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
      {
        // if you want to use a dynamic file location, just make the file name a member variable in your class
        using(FileStream fileStream = File.Open(@"c:\files\my_downloaded.file", FileMode.Create))
        {
          Stream source = response.GetResponseStream();
          int bytesRead;
          byte[] streamBuffer = new byte[1024*64];
          while ((bytesRead = source.Read(streamBuffer, 0, streamBuffer.Length)) > 0)
          {
            fileStream.Write(streamBuffer, 0, bytesRead);
          }
        }
      }
    }
  }
}