Which is best, single-threaded or multi-threaded server?

I need to create a simple client connection for transferring files using the C language (Linux).

The server accepts connections on port 10000, I don’t know whether it is better to create a new thread for each request or to create fixed numbers of threads and use the asynchronous technique.

CASE A: client --> server --> (new thread) --> process the request CASE B: SERVER --> create thread 1 - thread 2 - thread 3 then client1 --> server --> thread 1 client2 --> server --> thread 2 client3 --> server --> thread 3 client4 --> server --> thread 1 client5 --> server --> thread 2 client6 --> server --> thread 3 

In this case, thread 1 can handle many client requests.

My thoughts:

CASE 1: Faster, but spends a lot of memory

CASE 2: runs slower but uses low memory

I'm wrong?

+4
source share
7 answers

If you consider checking the architecture of widely used http-servers (nginx, lighttpd, apache), you will notice that those that use a fixed number of threads (the so-called "work threads", their number should depend on the number of processes on the server) is much faster than using a large thread pool. However, there are some very important points:

  • Implementing a workflow should not be as simple as it is seductive, or there will be no real performance gain. Each thread must implement each pseudo concurrency file using a state machine, processing several requests at once. No blocking operations are allowed here - for example, the time in the stream that is waiting for I / O from the hard disk to receive the contents of the file can be used to analyze the request for the next client. This is pretty complicated code to write.

  • A thread-based solution (with a reusable thread pool, like creating threads in hard work) is optimal when considering performance and coding time and code support. If your server does not have to process thousands of requests per second, you will get the ability to code in a fairly natural style of blocking without risking a complete failure.

  • As you can see, the "worker threads" themselves serve only static data, they proxy the dynamic execution of the script for some other programs. As far as I know (maybe not so), this is due to difficulties with non-blocking query processing with some unknown dynamic materials executed in their context. In any case, this should not be a problem in your case, since you are talking about simple file transfer.

The reason why a limited in-line solution is faster on systems with a lot of workload - thread http://en.wikipedia.org/wiki/Context_switch is a rather expensive operation, since it requires saving data from registers and loading new ones until while some other local stream data. If you have too many threads compared to the number of processes (for example, 1000 times more), a lot of time in the application will be wasted, just switching between threads.

So, the short answer to your question: "No, this has nothing to do with memory usage, the choice is the data type, the planned request / second count and the ability to spend a lot of time coding."

+5
source

There is no right answer. Depends on many things. And you need to choose yourself.

"CASE 1: faster, but wastes a lot of memory
"CASE 2: slower but uses low memory"

Wrong. Depends on many things. Creating threads is not so expensive (this is, but not so much), but if there are too many threads, you will have a problem.

It depends a lot on the load - what is the expected load? If so, let's say about 1000 requests per second - you know, if you create 1000 threads every second ..... this will be a disaster: D

Also - create as many threads as the processor can process without switching between them. There’s a big chance (depending on your program, of course), a single-core processor works a lot, much slower with 10 threads instead of 1 (or 2). It really depends on what these threads will do.

I would choose to create a thread pool and reuse threads.

+2
source

My first choice would be to make it single-threaded using select (2). If it weren’t so good, I would go with a thread pool solution. It will scale better.

There are times when creating a single thread per client is quite normal. I did this and it worked well for this application, usually around 100 clients - up to 1000 clients. That was 15 years ago. Today, the same application can handle 10,000 customers due to better hardware. Just keep in mind that one thread per client does not scale very well.

+2
source

I know that quite a lot of time has passed since you asked about this, but here I take your question from the point of view of someone who has already written several servers in C.

If your server is your own, completely dependent and independent of other codes, I would highly recommend that you do it single-threaded with non-blocking sockets and use epoll (Linux), kqueue (BSD) or WSAEventSelect (Windows).

This may require you to split the code, which otherwise would be “simple” for much smaller fragments, but if scalability is what you need, it will result in the loss of any streaming / selection based servers.

There was a wonderful article, once titled “C10K Problem,” which is fully focused on the problem of how to handle 10,000 concurrent connections. I actually learned from this myself, here is a link to it: http://www.kegel.com/c10k.html .

There is another great article that focuses on scalability called the Scalable Network, which you can find here: http://bulk.fefe.de/scalable-networking.pdf .

These are two excellent readings, hope this helps.

+1
source

It is completely up to you. There is no right or wrong answer. You have identified the pros and cons of both, and you are right with both of them; 1 faster, but more intense, 2 slower because customers can wait.

0
source

I would go with a pool of pre-created threads and reuse them when they are made with the current request that they are processing. Creating threads can be expensive, since these are basically kernel calls.

There is a project like "threadpool" here using pthreads. Perhaps you can get some ideas on how to implement it.

0
source

It really depends on what your server is doing.

I would recommend you do the simplest. This is probably a single-process model that multiplexes all available connections using, select, poll, libevent, or the like.

That is, if you are using TCP.

If you use UDP, this is even simpler because the application can do everything with one socket, so it can (possibly) use a blocking socket.

0
source

All Articles