libmicrohttpd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [libmicrohttpd] async answer to request


From: Christian Grothoff
Subject: Re: [libmicrohttpd] async answer to request
Date: Thu, 06 Dec 2012 08:12:30 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:16.0) Gecko/20121028 Thunderbird/16.0.2

On 12/06/2012 02:58 AM, Sebastiano Merlino wrote:
Hi Christian,
thanks for your reply. I implemented a "multi-thread external select" using your suggestion of providing the same external non blocking socket to multiple daemons.

My question now is, once the content_reader_callbacks returns 0 (because it has not still the data), the file descriptor seems to be removed from the library's fd_sets. Have I to store the file descriptor somewhere and re-insert it inside the write fd_set manually or there is another way?

MHD will put it back for you -- once your content reader callback returns non-zero!  You are waiting on some OTHER kind of event (presumably, after all, you wanted to produce the data asynchronously!), which you put into the select.  Once that OTHER event produces data, you call MHD_run again and it will again call your callback (without the FD being in 'select'); once your callback returns non-zero, MHD will put the socket back into the FD set.

Happy hacking!

Christian
Thanks,
Sebastiano


2012/12/5 Christian Grothoff <address@hidden>
On 12/04/2012 07:59 PM, Sebastiano Merlino wrote:
Hi all,
I am a big fan of the library and I realized several projects using it.

I am now trying to write a proxy using libmicrohttpd and curl; at the moment, I simply do a curl_easy_perform to the real service when I receive a request. I am using an INTERNAL_SELECT mode to manage requests with a pool of threads. I prefer to avoid THREAD_PER_CONNECTION to avoid explosions in terms of thread number and EXTERNAL_SELECT cause the limitation to a single thread.

Whenever I receive a call I have to wait the real server response in order to be able to give a response to the client, and when I have a lot of concurrent requests the pool is exhausted and connections are queued; so I am planning to use the curl multi interface to avoid the blocking on curl request and use an async io system to enhance parallelism.

Is it possible to delay my response (from libmirohttpd) to the time when I receive the response from curl without completely block one thread of the pool?

Am I completely blind and is there another and more simple system to do what I am trying to do?

Well, the 'simple' answer is the one I believe you already have given: use 'EXTERNAL_SELECT' mode, which allows you to return 0 from the content reader callback to say "no data yet" and to integrate MHD with a curl-multi event loop.  This is what we do in an HTTP(S) socks proxy in GNUnet, so I can safely say that it does work.  THREAD_PER_CONNECTION and curl_easy should also work, and --- unless you are on an embedded system --- I'm not sure the number of threads is a major issue (especially as with any select-based approach, you're limited to FD_SETSIZE (typically 1024) sockets and thus <512 connections).  So if we set the same concurrency limit for the thread-based approach, we need 512 threads, which is not all that scary given modern memory sizes on servers/desktops.

So anyway, as for scaling, I would suspect that the EXTERNAL_SELECT setup will first be limited by your FD_SETSIZE (unless you raised it) and not by the CPU being limited to a single thread.   So from an engineering point of view, I would urge you try that and only optimize further if you have established a need to do so via benchmarks.


Now, suppose you're on an embedded multi-core system with low-power cores, and your benchmarks tell you that multi-threading is needed; or maybe you do something else that is really expensive with the data or have some larger FD_SETSIZE. What to do in those cases?

Right now my answer would be to start multiple MHD-daemons, using the *same* listen socket.  If you open the listen socket yourself and pass it to MHD, you can have one listen socket be shared among multiple MHD daemon handles. So basically, you open one listen socket, start a bunch of threads, and have each of them run an external select loop around a per-thread MHD-daemon handle. This would essentially create an 'external select thread pool' mode. You will need to put the 'listen' socket into non-blocking mode (to avoid blocking one of the threads on a race for the socket --- note that the threads racing for the socket is _intended_ in this design, and the same race is used in the "internal select'-based thread-pool of MHD).

While I have not tried this 'external-select thread pool', I'm reasonably confident that it would work.  Still, if you do get it to work, I'm sure the list would appreciate an update ;-).


My 2 cents

Happy hacking!

Christian




reply via email to

[Prev in Thread] Current Thread [Next in Thread]