Asynchronous programming

I spent today learning about asynchronous programming and these are my notes related to it.

So, there are two kinds of systems -> synchronous and asynchronous.

In a synchronous system, you wait for a task to finish COMPLETELY before you move on to some other task

In an asynchronous system, you move on to some other task before it finishes. This allows more parallelism.

Event loop

  1. If we want to do something asynchronously in programming language, we use event loop
  2. Event loop can do following things:
    • register tasks to be executed
    • execute the tasks
    • delay execution of tasks
    • cancel tasks
  3. Every event is attached to event listener or else the event gets lost
  4. The main purpose of an event loop is:
    • run first function
    • while that function waits for IO, event loop pauses it and runs another function
    • when the first function returns result then it resumes it

 

Generators

  1. used to create iterators
  2. generators return multiple items but NOT as a list. They return items one by one

 

Difference between a normal callback function and a generator:

Normal callback function approach Generator approach
 After collecting ALL the results, it displays them altogether  It displays result as it finds them.

Advantages:

  • space efficient (no need to store all data at once)
  • time efficient (iteration may finish before all items are needed)
  • user-friendly (allows parallelism)

 

Yield

A function becomes a generator when it uses “yield”

 

Difference between a normal return statement and yield statement:

 Return  Yield
In a function which uses  return statement,

  • local variables are destroyed
  • the scope is destroyed
  • if function is called again, fresh set of variables are created
In a function which uses a yield statement,

  • local variables are not destroyed
  • scope is preserved
  • we can resume the function where we left off

 

Coroutine 

  1. Coroutine is basically used to allow to execute several tasks at once through non-preemptive multitasking
  2.  It passes control to each subroutine, wait for it until it finishes off, we can re-enter the routine later and continue
  3. Coroutine can suspend itself. But once it actually exits/returns, then it cannot be resumed.
  4. There is no need to add a yield statement in a coroutine but the function called by a coroutine can have a yield statement

 

Future

This is the most interesting concept.

  1. Future is one way to write asynchronous code
  2. Future is result of work that has not been completed yet
  3. future() method does not return a result, but returns a future object. When the task completes, the result is returned eventually. Meanwhile, next code is executed.
  4. When do we know that state of future has changed?
    • when set_result() is called
  5. How to check that the task taken by future has been completed?
    • by using event loop -> it watches state of future object to indicate that its done
  6. Future is a way of performing many tasks in parallel, in efficient, non-blocking way
  7. There are two cases:
    • When computation of task does not complete -> future does not complete.
    • When computation of task completes and returns either a result or exception -> future completes
  8. The result of returned by future() can be:
    • value -> future completes successfully
    • exception -> future has failed with an exception
  9. Future has an important property.
    • It can be assigned only once
    • Once it has been given a value, it becomes immutable and can never be over-written

 

Task

  1. a subclass of future
  2. wraps a coroutine
  3. when coroutine is finished, it returns result then task is finished

 

 

Conclusion

  1. For asynchronous programming, we need event loop
  2. We register our tasks/ futures in the event loop
  3. The event loop schedules them and executes them
  4. Callbacks are used so that we are notified when tasks/ future return results
  5. Coroutines are wrapped in tasks/ futures
    • when yield is finding, coroutine is paused
    • when yield gets a value, coroutine continues
  6. If coroutine doesnot return a value but returns an exception, then task fails.

 

This is a simple program i tried with Python’s asyncio module:

Screenshot from 2016-04-27 17-41-52

 

Python asyncio module

 

@asyncio.coroutine:

basically defines a coroutine

 

loop = asyncio.get_event_loop()

creates an event loop

 

loop.run_forever()

runs  a loop until stop() method is called

Asynchronous programming

Running ircb instance

ircb is a irc bouncer. A bouncer connects to irc server and maintains a persistant connection. Instead of connecting to IRC server, connect to the bouncer. Even if you disconnect your client, it stays connected. If you log in after some time, it shows you the messages that you have missed.

You can find the source code of ircb here.

Following are the screenshots to show the steps i had done to run ircb instance:

Screenshot from 2016-04-17 18-43-31
Clone the repo

 

Screenshot from 2016-04-16 18-10-23
Install dependencies

 

Screenshot from 2016-04-16 18-15-03
Create virtual environment

 

Screenshot from 2016-04-16 18-16-59
Activate virtual environment

 

Screenshot from 2016-04-16 18-17-59
Install requirements

 

Screenshot from 2016-04-16 18-23-09
Create custom location directory

 

Screenshot from 2016-04-16 18-23-57
Create settings file in custom location

 

Screenshot from 2016-04-16 18-24-37
Copy settings

 

Screenshot from 2016-04-16 18-25-13
Export settings

 

Screenshot from 2016-04-16 18-25-39
Run setup.py

 

me1
Create a new user

 

me2
Create network for that user

 

runserver
Run server
1
Open the endpoint using a IRC client.

Here I have used Hexchat which is a popular IRC client for Fedora. You can use xchat, irssi etc

I have used the most popular IRC network Freenode. Freenode listens on port 6667 for non-SSL and 6697 for SSL.

 

2
Add information for your bouncer

Servers of this IRC network: irc.freenode.net 6667

You can also add channels under “autojoin” tab.

3
Screenshot 1: connecting to server

 

4
Screenshot: Connected to server

 

5
Joining channel1 : #dgplug

The last step is to add some channels. Use the command “/join #<channel name>” to join a channel.

<channel name> is the name of a channel you want to join, such as #fedora, #dgplug, #waartaa.

6
Joining channel2: #waartaa

Now you never have to worry about missing another message in an IRC channel again!

Running ircb instance