I'm interesting what are actual costs of threads creation in Java, C# and C++? I know that when thread is creating a bunch of operations must be done: allocate thread stack, initialize descriptors, etc.
But I'm interesting in actual costs. C# and Java use different VM's and different JITs and C++ executes native code. So thread creation time is different in all of these languages. I also heard that thread creation in Java is much slower that in C#. Can someone give authorative answers and explanations on this issue?
Benchmarking the creation of 10,000 threads in C#, Java, and Visual C++:
class Program
{
static void Main(string[] args)
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 10000; i++)
{
Thread thread = new Thread(DoNothing);
thread.Start();
}
watch.Stop();
Console.WriteLine(watch.Elapsed);
}
static void DoNothing()
{
//Do Nothing
}
}
Result: 1.7638042 seconds
public class ThreadBencher {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
//Do nothing
}
};
long startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
Thread thread = new Thread(r);
thread.start();
}
long stopTime = System.nanoTime();
long totalTime = stopTime - startTime;
System.out.print(totalTime);
}
}
Result: 1.514557805 seconds (or 1514557805 nanoseconds)
DWORD WINAPI DoNothing( LPVOID lpParam )
{
return 0;
}
void main()
{
HANDLE ourThreadHandle = 0;
SYSTEMTIME st1;
SYSTEMTIME st2;
int i;
GetLocalTime(&st1);
for (i = 0; i < 10000; i++) {
ourThreadHandle = CreateThread( NULL, 0, DoNothing, 0, 0, NULL);
}
GetLocalTime(&st2);
double dblSt1 = st1.wSecond + (st1.wMilliseconds / 1000);
double dblSt2 = st2.wSecond + (st2.wMilliseconds / 1000);
double result = dblSt2 - dblSt1;
cout << st1.wSecond << "." << st1.wMilliseconds << endl;
cout << st2.wSecond << "." << st2.wMilliseconds << endl;
}
Result (after manual calculation from output): 0.925 seconds
(Disclaimer: I don't know C++ very well so the C++ code is pretty patched together)
Note: This was done in a 64-bit Windows 8 environment.
This is what that happens when a thread is created.
When a new thread is created it shares its code section, data section and operating system resources like open files with other threads. But it is allocated its own stack, register set and a program counter.
Thread Costs
Threading has a real cost to your program (and the system) in terms of memory use and performance. Each thread requires the allocation of memory in both the kernel memory space and your program’s memory space.
The core structures needed to manage your thread and coordinate its scheduling are stored in the kernel using wired memory. Your thread’s stack space and per-thread data is stored in your program’s memory space.
Most of these structures are created and initialized when you first create the thread—a process that can be relatively expensive because of the required interactions with the kernel.
Some of these costs are configurable, such as the amount of stack space allocated for secondary threads. The time cost for creating a thread is a rough approximation and should be used only for relative comparisons with each other. Thread creation times can vary greatly depending on processor load, the speed of the computer, and the amount of available system and program memory.
Threads do not consume memory (aside from their stack, which is constant-sized); processes consume memory. The whole point of threads is that they share process state.
Common Language Runtime (CLR) threads have their stack space set to (comitted by the CLR) 1MB (4MB for 64 bit code threads) per default.
In C++ it reserves 1MB for the stack (it maps its address space), but it is not necessarily allocated in the physical memory, only a smaller part of it. If the stack grows more than that a page fault is generated and more physical memory is allocated.
Java thread creation is expensive because there is a fair bit of work involved:
A large block of memory has to be allocated and initialized for the thread stack.
System calls need to be made to create / register the native thread with the host OS.
Descriptors needs to be created, initialized and added to JVM internal data structures.
It is also expensive in the sense that the thread ties down resources as long as it is alive; e.g. the thread stack, any objects reachable from the stack, the JVM thread descriptors, the OS native thread descriptors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With