Ruby threads require care when writing an extension - especially when the extension does anything over a network. In the case of curb, it's often used as a replacement to the built in ruby net/http library.
The basic experiment goes, you use a web service like, amazon or google within your web application. Let's say you've just start porting some parts of your rails application to merb, or even just a simple mongrel handler. You're hoping to increase the throughput of this application by taking advantage of the increased concurrency gain by using less locking. This works great testing locally. Only one thing we forgot, the threads in ruby are cooperative. This means, any one thread can block all other threads from running. So, while we spent this extra time and energy to rewrite specific parts of our application to increase its concurrency - we forgot that ruby threads don't always mix well with native extensions. Occasionally, one of these service calls will take a bit longer then normal. When this happens, all our threads are blocked. To make matters worse, we're actually not seeing too much of a throughput improvement after making our changes.
The few tests we did show a speed improvement for a single request, but multiple concurrent requests or throughput has stayed about the same, because the Curl::Easy.perform call is blocking all other ruby threads from running at the same time. Meaning, we mightiest well just leave our calls in the rails controller and move on right?
Well, by now you probably realized I'm not that kind of programmer... Giving up like this isn't why I like to write code... So, doing a little more digging I realized the answer is rb_thread_select.
Using rb_thread_select in place of select and making calls to libcurl's multi interface instead of curl_easy_perform, I've made it possible to run multiple Curl::Easy.perform calls concurrently. You'll still probably see much higher throughput using the Curl::Multi interface, but this should help those using the more direct Curl::Easy interface. I also updated the Curl::Multi interface to use ruby's rb_thread_select, meaning it can be used within multiple ruby threads as well.
Remember this does not mean I made Curl::Easy or Curl::Multi thread safe, but it means multiple instances of those objects can be used within multiple threads, running in parallel.
You can get my curb changes on github.
