Speed of synchronized
Christian Köstlin via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sun Oct 16 01:41:26 PDT 2016
Hi,
for an exercise I had to implement a thread safe counter.
This is what I came up with:
---SNIP---
import std.stdio;
import core.thread;
import std.conv;
import std.datetime;
static import core.atomic;
import core.sync.mutex;
int NR_OF_THREADS = 100;
int NR_OF_INCREMENTS = 10000;
interface Counter {
void increment() shared;
long get() shared;
}
class ThreadUnsafeCounter : Counter {
long counter;
void increment() shared {
counter++;
}
long get() shared {
return counter;
}
}
class ThreadSafe1Counter : Counter {
private long counter;
synchronized void increment() shared {
counter++;
}
long get() shared {
return counter;
}
}
class ThreadSafe2Counter : Counter {
private long counter;
__gshared Mutex lock; //
http://forum.dlang.org/post/rzyooanimrynpmqlywmf@forum.dlang.org
this() shared {
lock = new Mutex;
}
void increment() shared {
synchronized (lock) {
counter++;
}
}
long get() shared {
return counter;
}
}
class AtomicCounter : Counter {
private long counter;
void increment() shared {
core.atomic.atomicOp!"+="(this.counter, 1);
}
long get() shared {
return counter;
}
}
void main() {
void runWith(Counter)() {
shared Counter counter = new shared Counter();
void doIt() {
Thread[] threads;
for (int i=0; i<NR_OF_THREADS; ++i) {
threads ~= new Thread({
for (int i=0; i<NR_OF_INCREMENTS; ++i) {
counter.increment();
}
});
}
foreach (Thread t; threads) {
t.start();
}
foreach (Thread t; threads) {
t.join();
}
}
auto duration = benchmark!(doIt)(1);
writeln(typeid(counter), ": got: ", counter.get(), " expected: ",
NR_OF_THREADS * NR_OF_INCREMENTS, " in ", to!Duration(duration[0]));
}
runWith!(AtomicCounter)();
runWith!(ThreadSafe1Counter)();
runWith!(ThreadSafe2Counter)();
runWith!(ThreadUnsafeCounter)();
void doIt2() {
auto mutex = new Mutex;
int numThreads = NR_OF_THREADS;
int numTries = NR_OF_INCREMENTS;
int lockCount = 0;
void testFn() {
for( int i = 0; i < numTries; ++i ) {
synchronized( mutex ) {
++lockCount;
}
}
}
auto group = new ThreadGroup;
for( int i = 0; i < numThreads; ++i )
group.create( &testFn );
group.joinAll();
assert( lockCount == numThreads * numTries );
}
auto duration = benchmark!(doIt2)(1);
writeln("from example got: ", to!Duration(duration[0]));
}
---SNIP---
For completeness I added also the example from core.sync.mutex
(https://dlang.org/phobos/core_sync_mutex.html) at the end.
My question now is, why is each mutex based thread safe variant so slow
compared to a similar java program? The only hint could be something
like:
https://blogs.oracle.com/dave/entry/java_util_concurrent_reentrantlock_vs that
mentions, that there is some magic going on underneath.
For the atomic and the non thread safe variant, the d solution seems to
be twice as fast as my java program, for the locked variant, the java
program seems to be 40 times faster?
btw. I run the code with dub run --build=release
Thanks in advance,
Christian
More information about the Digitalmars-d-learn
mailing list