August 26, 2019

Testing the performance of RESTful API with Flask

On the first look, the idea to use a network sockets for communicating between different programs sounds not very common. Instead the literature recommends to use language bindings like SWIG, Python ctypes to use an existing C library from within Python. But suppose the idea is to use as middle layer the network protocol, how well is the performance if all the data are send over the network card to the localhost device?

At first, we need a running flask server plus a python client who gets access to the data.
# server.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hallo Welt"
if __name__ == "__main__":
    app.run()

# client.py
import requests, time
for i in range(1000):
  res = requests.get("http://127.0.0.1:5000/")
  print(i,res,res.text)
  time.sleep(1)
After running the server.py it's possible to retrieve the information from a webbrowser or by starting the curl command on the command line “curl -v http://127.0.0.1:5000/”. In both cases, the response is a simple hello world which is send as a network message.

The next step is to make a small performance test. We can remove the “time.sleep(1)” statement which means, that the for loop of the client is trying to retrieve the information in the shortest amount of time. On my standard notebook the measured time was 4.8 seconds for 1000 requests. This is equal 208.3 requests per seconds. Only to get the numbers right, a normal computer game runs with 30 fps, which means that in a single seconds 30 requests are answered by the game engine. 208.3 requests per second from the flask server is equal to 200 frames per second, which is fast enough for most games.

It's important to notice, that this speed was reached not over a wired connection but with the localhost interface. It measures the time, to communicate between two local apps on the same computer.

The conclusion is, that FLASK and RESTful in general which is available for C++ as well, is fast enough as a communication interface between different applications. What does that mean for programmers? It means, that it will become very easy to connect different programming languages together. No matter if the sourcecode was written in Python, C++, C#, Java, Go, plan C, Forth or whatever. With the help of a RESTful API it's possible to send data between all the programs.

Details
If the server.py runs in the background, every request is written to the commandline:
127.0.0.1 - - [25/Aug/2019 16:35:54] "GET / HTTP/1.1" 200
Which means, that the server.py FLASK instance has received a request and delivered the “Hello world” message back. On the other hand, the client.py application produces a load on the server:
0  Hallo Welt
1  Hallo Welt
2  Hallo Welt
It sends a GET request, and retrieves the textual information in exchange. Why is this something which is important? Because the normal case is, that different programming languages can't communicate to each other. It's hard embedded Python Code in a C application, or to transmit from a Java application a string to a C++ library. In some cases wrappers are available, but these tools are not working very robust and the common understanding is, that the problem is located within a certain programming language. That means, the Python language has to be blamed, because it's not possible to import an existing C++ library.

The problem is not located within a certain programming language, because apart from Python all the other languages like C++, Java or C# have the same problem to communicate with sourcecode written in a different language. The problem is, that an individual language like C# has a certain environment. For example it comes with a virtual machine, some preprogrammed code and a pipeline how to convert the sourcecode into a binary file. This workflow makes it hard for a different programming to get access.

What most programmers are doing is to stay within a single language. They are using Python or C++ for creating an application but it's not allowed to mix both languages. And exactly this problem can be solved with FLASK like RESTful services. On the higher instance of a localhost it's possible to communicate between different programming languages back and forth. The only precondition is, that a certain language is able to send data with the RESTful standard.

Speed up with crow and C++
RESTful service are available outside the Python ecosystem as well. In the C++ domain, the crow package is trying to imitate the FLASK library. The sourcecode for running a simple hello world server has to be compiled with the -I option which includes the path to the crow include directory. The client software is the same like in the FLASK example, except that the URL has a different port number.
// g++ -std=c++14 -lboost_thread -lboost_system -pthread -Ipath/to/crow hello.cpp 
#include "crow.h"
int main()
{
    crow::SimpleApp app;
    CROW_ROUTE(app, "/")
    ([]() {
        return "Hello world!";
    });
    app.port(18080).run();
}

# client.py
import requests, time
for i in range(1000):
  res = requests.get("http://127.0.0.1:18080/")
  print(i,res,res.text)
  time.sleep(1)
After running both programs in parallel it make sense to test the performance again. This time, the C++ crow service is much faster than the previous FLASK server. On the same standard notebook, 1000 requests are handled in 2.64 seconds, compared to 4.8 seconds in the previous trial. Or to give the other point of view: the combination of a C++ based RESTful server provides 379 requests per seconds. If the performance is greater, if the server and the client are programmed both in C++ is unclear.

What makes the situation comfortable is, that the same technique can be used together with different programming language. It's possible to combine Java, Python, C++, C, PHP, Javascript and C#. That means, it's possible to write the backend in Python and the frontend in Java, or the backend in C++ and the frontend in C#. What makes this technique so powerful is, that there is no need to convince a certain programmer to leave his normal programming language and switch to a different one which works better. The reality is, that real python programmer never would migrate to C++, and an expert Java coder is not interested in learning Python. All of the programmers are right, their home language is the best one and there is no need to switch to a different computer language.

The disadvantage is, that against the self-description, RESTful and the C++ crow implementation are not lightweight. The resulting a.out binary file contains a complete webserver and has a size of 1.4 megabyte.

The interesting question is how much performance is needed in reality? Suppose the idea is to write a computer game which contains of frontend and a backend.The interesting point is, that even the frontend is rendering 60 fps, there is no need to send with this speed data back and forth. In most cases it's enough to update the game state with 5-10 frames per seconds. This is way more faster, than a human player can react. This kind of latency is reached easily by all RESTful implementations.