NIO+Multithreaded TCPSocket listener, very low cpu utilisation
ade90036
andrea.rizzini at gmail.com
Tue Nov 14 19:57:54 UTC 2017
Hi Forum,
Let's cut the chase, i'm a newby in Dlang. I have 15+ years
experience in java and 7+ years experience in C++.
I found D very fascinating and the sugar coated syntax very
appealing to my style of coding. (groovy like)
I've been trying to learn Dland and bring it thought the motions
by creating a very simple and basic TCPSocket listerner that when
you send a request it responds with an HTTP response over a
specific port. (localhost:4445)
I have the code working on a worked thread and when the socket
accept() it defers the processing of the request (socket) in a
different thread backed by TaskPool(8).
i have 8 logical core, which is a macBook pro retina 16gb, i7.
What i'm expecting to see is the CPU of my 8 core I7 go through
the roof and nearly melt (hope not) but at-least have the fan on
at sustainable level and obtain full CPU utilisation.
What i'm benchmarking it against is a JAVA NIO2 implementation.
This implementation achieves very high CPU utilisation and high
throughput. The process utilisation averages 400% at times and
the fan is really searching for cold air. (Niceeee)
However, when i run the Dlang program i see i very poor CPU
utilisation. The fan is always in silent mode.
Not sure if you are familiar with MacOS cpu metrics, but they are
based per core. So dland program reports 100% under the process
monitor (which equates to one core) and the overall system CPU
utilisation is 13%.
I would have expected to see a much higher cpu utilisation but it
is not happening. I have been trying different variation of the
same implementation but not luck.
I'm starting to suspect that this is an BUG related to the macOS
but i would like to confirm or atleast have a second pair of eyes
having a look.
```Code
import std.algorithm : remove;
import std.conv : to;
import core.thread: Thread;
import std.socket : InternetAddress, Socket, SocketException,
SocketSet, TcpSocket, SocketShutdown;
import core.time : Duration, dur;
import std.stdio : writeln, writefln;
import std.parallelism : task, TaskPool;
void main(string[] args)
{
ushort port;
if (args.length >= 2)
port = to!ushort(args[1]);
else
port = 4447;
auto listener = new TcpSocket();
assert(listener.isAlive);
listener.blocking = false;
listener.bind(new InternetAddress(port));
listener.listen(100);
writefln("Listening on port %d.", port);
auto taskPool = new TaskPool(8);
new Thread({
auto listeningSet = new SocketSet();
while(true) {
listeningSet.add(listener);
if (Socket.select(listeningSet, null, null,
dur!"nsecs"(150)) > 0) {
if (listeningSet.isSet(listener)) //
connection request
{
Socket socket = null;
scope (failure)
{
writefln("Error accepting");
if (socket)
socket.close();
}
socket = listener.accept();
assert(socket.isAlive);
assert(listener.isAlive);
//writefln("Connection from %s established.",
socket.remoteAddress().toString());
auto task = task!handle_socket(socket);
taskPool.put(task);
}
}
listeningSet.reset();
}
}).start();
}
void handle_socket(Socket socket) {
auto socketSet = new SocketSet();
while(true) {
socketSet.add(socket);
if (Socket.select(socketSet, null, null,
dur!"nsecs"(150)) > 0) {
char[1024] buf;
auto datLength = socket.receive(buf[]);
if (datLength == Socket.ERROR)
writeln("Connection error.");
else if (datLength != 0)
{
//writefln("Received %d bytes from %s: \"%s\"",
datLength, socket.remoteAddress().toString(), buf[0..datLength]);
//writefln("Writing response");
socket.send("HTTP/1.1 200 OK
Server:
dland:v2.076.1
Date: Tue, 11 Nov
2017 15:56:02 GMT
Content-Type:
text/plain; charset=UTF-8
Content-Length: 32
<html><head></head><body>Hello World!</body></html>");
}
// release socket resources now
socket.shutdown(SocketShutdown.BOTH);
socket.close();
break;
}
socketSet.reset();
}
}
```
You help in understanding this matter is extremelly helpfull.
Regards
More information about the Digitalmars-d-learn
mailing list