67

I was reading how Clojure is 'cool' because of its syntax + it runs on the JVM so it is multithreaded etc. etc.

Are languages like ruby and python single threaded in nature then? (when running as a web app).

What are the underlying differences between python/ruby and say java running on tomcat?

Doesn't the web server have a pool of threads to work with in all cases?

Omar Qureshi
  • 8,963
  • 3
  • 33
  • 35
Blankman
  • 259,732
  • 324
  • 769
  • 1,199
  • 4
    Where did you read this? [Citation needed] – Kris Jun 21 '10 at 16:32
  • @ircmaxell, (for what its worth:) you should post this as an answer together with a citation – chiccodoro Jun 21 '10 at 16:36
  • sorry its more of, clojure markets ' robust infrastructure for multithreaded programming' so I (wrongly) assuming other frameworks are not multi-threaded. – Blankman Jun 21 '10 at 17:02
  • Bear in mind that there's differences between languages and their implementations. Are you asking whether certain languages have multiple thread capability, or whether certain implementations of them do? – David Thornley Jun 22 '10 at 21:25

13 Answers13

63

Both Python and Ruby have full support for multi-threading. There are some implementations (e.g. CPython, MRI, YARV) which cannot actually run threads in parallel, but that's a limitation of those specific implementations, not the language. This is similar to Java, where there are also some implementations which cannot run threads in parallel, but that doesn't mean that Java is single-threaded.

Note that in both cases there are lots of implementations which can run threads in parallel: PyPy, IronPython, Jython, IronRuby and JRuby are only few of the examples.

The main difference between Clojure on the one side and Python, Ruby, Java, C#, C++, C, PHP and pretty much every other mainstream and not-so-mainstream language on the other side is that Clojure has a sane concurrency model. All the other languages use threads, which we have known to be a bad concurrency model for at least 40 years. Clojure OTOH has a sane update model which allows it to not only present one but actually multiple sane concurrency models to the programmer: atomic updates, software transactional memory, asynchronous agents, concurrency-aware thread-local global variables, futures, promises, dataflow concurrency and in the future possibly even more.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • 1
    +1 So, are the *"default"* implementations of Python and Ruby ( you know those where Guido and Matz participate ) *single threaded*? – OscarRyz Jun 21 '10 at 16:47
  • I cannot speak for Python, but as for Ruby, there is no such thing as a "default implementation". There is a Language Specification and there is a bunch of compilers and/or interpreters that implement that Language Specification. Every compiler or interpreter that faithfully implements the specification is a Ruby implementation and none of those is in some way special or "default" or whatever. – Jörg W Mittag Jun 21 '10 at 16:53
  • 14
    Technically the stock implementations "are multi-threaded". But because of the Global Interpreter Lock only one thread can execute at a time. So in essence...no they are not multi-threaded. This applies to both Ruby and Python. – Timothy Baldridge Jun 21 '10 at 16:54
  • 1
    @Jorg, he defined the default ruby to be "the one Matz works on", which i think is a pretty fair default. – Peter Recore Jun 21 '10 at 18:34
  • 5
    It's a bit of an overstatement to say CPython cannot run threads in parallel - the threads run concurrently but cannot make use of multiple processors except in defined locations (like waiting for I/O on a file or socket, or when using some C libraries, for instance lxml allows parallel execution when parsing). The performance penalty on multiple processors only affects a small number of situations. – Ian Bicking Jun 21 '10 at 20:18
  • 2
    Ruby version 1.8 has two main implementations: MRI and JRuby. And as far 1.9 goes, YARV is the most common. So definetly you could say that MRI/YARV are the defaults. And by definition of default the most popular and widespread implementations are considered. And thats probably pretty clear to anyone working with ruby so i see no reason to pick over wording. Just my 2 cents. – Tanel Suurhans Jun 21 '10 at 20:37
  • 2
    To paraphrase the lawyer joke, the implementation of ruby used by 95% of users (YARV/MRI) gives the language a bad name! – Andrew Grimm Jun 21 '10 at 23:03
21

A confused question with a lot of confused answers...

First, threading and concurrent execution are different things. Python supports threads just fine; it doesn't support concurrent execution in any real-world implementation. (In all serious implementations, only one VM thread can execute at a time; the many attempts to decouple VM threads have all failed.)

Second, this is irrelevant for web apps. You don't need Python backends to execute concurrently in the same process. You spawn separate processes for each backend, which can then each handle requests in parallel because they're not tied together at all.

Using threads for web backends is a bad idea. Why introduce the perils of threading--locking, race conditions, deadlocks--to something inherently embarrassingly parallel? It's much safer to tuck each backend away in its own isolated process, avoiding the potential for all of these problems.

(There are advantages to sharing memory space--it saves memory, by sharing static code--but that can be solved without threads.)

Glenn Maynard
  • 55,829
  • 10
  • 121
  • 131
  • I'm pretty sure that of the four real-world Python implementations, three *do* support truly concurrent threads. Or, to be more precise, threads synchronized by very fine-grained locks strategically placed around a few very small datastructures instead of a giant monster lock across the entire interpreter. – Jörg W Mittag Jun 22 '10 at 00:21
  • It depends on your definition of "real-world", of course, but I won't claim to have tried every implementation either. – Glenn Maynard Jun 22 '10 at 04:58
  • 1
    "You spawn separate processes for each backend" this can be a huge memory/resource hog, what if i need to spawn 50+ processes? it is much easier to synchronize threads like Jorg mentions above putting locks in strategic places and managing it that way rather then spawning a new process for each task. – Syler Apr 06 '14 at 06:21
  • 1
    There's *nothing* easier about using threads and locks. It's orders of magnitude harder to debug. – Glenn Maynard Apr 11 '14 at 16:03
  • @Syler What is the purpose to have so many separate processes? The common way in the web is to have this number close to the number of CPUs. Where each of the process can have as many threads as you want. This threads will have some blocking operations where context switching will occur between them. So that you can get the efficiency near to the "true" multi-threaded languages. Am I right? – sunki Jun 27 '18 at 16:34
  • This is a great answer (better than the selected one) but I think you might be confusing [concurrency with parallelism](https://stackoverflow.com/a/1050257/2259743). Imo "it doesn't support concurrent execution in any real-world implementation" should be "it doesn't support _parallel_ execution" – spygi May 03 '19 at 17:53
15

CPython has a Global Interpreter Lock which can reduce the performance of multi-threaded code in Python. The net effect, in some cases, is that threads can't actually run simultaneously because of locking contention. Not all Python implementations use a GIL so this may not apply to JPython, IronPython or other implementations.

The language itself does support threading and other asynchronous operations. The python libraries can also support threading internally without exposing it directly to the Python interpreter.

If you've heard anything negative about Python and threading (or that it doesn't support it), it is probably someone encountering a situation where the GIL is causing a bottleneck..

James Schek
  • 17,844
  • 7
  • 51
  • 64
6

Certainly the webserver will have a pool of threads. That's only outside the control of your program. Those threads are used to handle HTTP requests. Each HTTP request is handled in a separate thread and the thread is released back to pool when the associated HTTP response is finished. If the webserver doesn't have such a pool, it would have been extremely slow in serving.

Whether a programming language is singlethreaded or multithreaded dependens on the possibility to programmatically spawn new threads using the language in question. If that isn't possible, then the language is singlethreaded, for example PHP. As far as I can see, both Ruby and Python supports multithreading.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • As a related/more specific question: Would a person new to Ruby/Rails need to do anything fancy when deploying a web app or CGI script to get that webserver pool functionality? i.e. if I were to just copy my .rb files to a webserver, would the webserver be able serve multiple concurrent requests using the same code, or is there some fancy config needed? – LoveMeSomeCode Jun 21 '10 at 16:56
  • Well, there's generally a bit more to deploying a Ruby app than just copying files over and pointing the webserver at them, but yes, the server handles spawning new threads (or processes) by itself. – Xiong Chiamiov Jul 15 '10 at 18:49
5

The short answer is yes, they are single threaded.

The long answer is it depends.

JRuby is multithreaded and can be run in tomcat like other java code. MRI (default ruby) and Python both have a GIL (Global Interpreter Lock) and are thus single threaded.

The way it works for web servers is further complicated by the number of available server configurations. For most ruby applications there are (at least) two levels of servers, a proxy/static file server like nginx and then the ruby app server.

Nginx does not use threads like apache or tomcat, it uses non-blocking events (and I think forked worker processes). This allows it to deal with higher levels of concurrency than would be allowed with the overhead and scheduling inefficiencies of native threads.

The various ruby apps servers also work in different ways to get high throughput and concurrency without threads. Thin uses libev and the asynchronous evented model like Nginx. Mongrel uses a round-robin pool of worker processes. Unicorn uses native Unix IPC (select on a socket) to load balance to a pool of forked processes through one master proxy socket.

Threads are only one way to address concurrency. Multiple processes and evented models are a different approach that ties in well with the Unix base. This is fundamentally different from the way Java treats the world.

Ben Hughes
  • 14,075
  • 1
  • 41
  • 34
  • short answer is wrong, Python is multi-threaded, it is just that the C implementation does not allow true concurrency of the threads, but it is still multi-threaded. –  Jun 21 '10 at 16:58
  • when does the global interpreter lock kick in the prevent a true multi-threaded enviro? – Blankman Jun 21 '10 at 18:06
  • 1
    The GIL protects a Python thread from entering the bytecode interpeter if there already is one. This means that *only* running inside the interpreter is protected. For example, multiple Python threads running C code from C extensions is perfectly fine. Also, multiple C threads running is also fine. The only thing that doesn't work is multiple *Python* threads running *Python* code. (Of course, C extensions themselves may have *their own* locks. And obviously, if a C thread from an extension wants to enter the interpreter on behalf of a Python thread, then *it* needs to get the GIL as well.) – Jörg W Mittag Jun 21 '10 at 19:11
  • @JörgWMittag: Is it the same for the GIL of MRI Ruby ? – Sriram R Apr 03 '16 at 12:38
5

Python

Let me try to put it more simply than the more detailed answers.

The heart of the answer here doesn't really have to do with Python being single-threaded versus multi-threaded. It has a more to do with threading versus multiprocessing.

Saying Python is "single-threaded" doesn't really capture reality, because you can certainly have more than one thread running in a Python process. Just use the threading library, and create more than one thread. There, now you have just proven that Python isn't single-threaded.

But using multiple threads in Python does NOT mean you're using multiple CPU processors concurrently. In fact, the Global Interpreter Lock prevents this. So this is where questions arise.

Basically, threading in Python cannot be used for parallel CPU computation. But you CAN do parallel CPU computation with Python by using multiprocessing instead of multi-threading.

I found this article very helpful when researching this: https://timber.io/blog/multiprocessing-vs-multithreading-in-python-what-you-need-to-know/ . It includes real-world examples of when you'd want to use multiprocessing versus multi-threading.

Mark_io
  • 81
  • 1
  • 4
4

Most languages don't define single or multithreading. Usually, that is left up to the libraries to implement.

That being said, some languages are better at it than others. CPython, for instance, has issues with interpreter locking during multithreading, Jython (python running on the JVM) does not.

Some of the real power of Clojure (IMO) is that it runs on the JVM. You get multithreading and tons of libraries for free.

ablerman
  • 1,523
  • 1
  • 12
  • 20
  • why closure over java? its short syntax? – Blankman Jun 21 '10 at 16:44
  • 4
    @Blankman - why *any* language over any other? There are many, **many** reasons why one may choose Clojure over Java or vice versa; suffice to say, a one-liner response in a comment would be insufficient to address the question. ablerman's point was simply that Clojure can piggyback on one of Java's major advantages as well as offering its own. – Andrzej Doyle Jun 21 '10 at 16:49
  • +1 to Andrzej comment. Also I would say that for me the Syntax is what drew me to Clojure away from Python and C#. And this coming from a guy who finds Java appalling. To each his own. – Timothy Baldridge Jun 21 '10 at 16:57
1

A few interpreted programming languages such as CPython and Ruby support threading, but have a limitation that is known as a Global Interpreter Lock (GIL). The GIL is a mutual exclusion lock held by the interpreter that prevents the interpreter from concurrently interpreting the applications code on two or more threads at the same time, which effectively limits the concurrency on multiple core systems.

from wikipedia Thread

tkr
  • 1,331
  • 1
  • 9
  • 27
  • 2
    First of all, there is no such thing as an "interpreted programming language". Interpretation is a trait of the implementation, not the language; *any* language can be implemented by either a compiler or an interpreter, most are implemented by both. Secondly, CPython is not programming language, it's programming language *implementation*. Thirdly, it's not even an interpreter, CPython is a *compiler*. Fourth, neither Python nor Ruby have a GIL. *One* Python implementation and *two* (out of a dozen) Ruby implementations have a GIL, but again, a GIL is not a trait of the language not the impl. – Jörg W Mittag Jun 21 '10 at 16:58
1

keeping this very short..

Python supports Multi Threading.

Python does NOT support parallel execution of its Threads.


Exception:

Above statement may vary with implementations of Python not using GIL (Global Interpreter Locking).

If a particular implementation is not using GIL, then, that would be Multi Threaded as well as support Parallel Execution

Aditya Rewari
  • 2,343
  • 2
  • 23
  • 36
0

Ruby

The Ruby Interpreter is single threaded, which is to say that several of its methods are not thread safe.

In the Rails world, this single-thread has mostly been pushed to the server. So, you'll see nginx running with a pool of mongrel servers, each of which has an interpreter in memory, processes 1 request at a time, and in its own thread.

Passenger, running "ruby enterprise" brings the concept of garbage collection and some thread safety into Rails, and it's nice.

Still work to be done in Rails on this area, but it's getting there slowly -- but in general, the idea is to have multiple services and servers.

Jesse Wolgamott
  • 40,197
  • 4
  • 83
  • 109
  • 2
    "The Ruby Interpreter is single threaded": Wrong. First of all, there is no such thing as "the Ruby Interpreter". There is about a dozen or so of those, and all but one of them are multi-threaded. "Passenger, running Ruby Enterprise Edition brings the concept of garbage collection": Wrong. *All* Ruby Implementations have garbage collection and have *always* had garbage collection ever since the very first version 17 years ago. Also, REE has nothing to do with thread-safety. And it doesn't "bring anything into Rails", in fact, it has nothing to do with Rails, it's just a Ruby implementation ... – Jörg W Mittag Jun 21 '10 at 16:48
  • ... like any other. (In fact, it's not even really even a Ruby implementation, it's just a small set of patches to MRI.) – Jörg W Mittag Jun 21 '10 at 16:49
  • You're right about the garbage collection, poor choice of words; I meant that it allows connections and other memory objects to be reused across 'passengers', resulting in a lower memory footprint and a higher concurrency count. YMMV, but in my experience, it's a good thing. – Jesse Wolgamott Jun 21 '10 at 17:55
0

How to untangle the knots in al those threads...

Clojure did not invent threading, however it has particularly strong support for it with Software Transactional Memory, Atoms, Agents, parallel map operations, ...

All other have accumulated threading support. Ruby is a special case as it has green threads in some implementations which are a kind of software emulated threads and do not use all the cores. 1.9 will put this to rest.

Regarding web servers, no they do not always work multithreaded, apache has traditionally ran as a flock of daemons which are a pool of separate single threaded processes. Now currently there are more options to run apache servers.

To summarize all modern languages support threading in one form or another.

The newer languages like scala and clojure are adding specific support to improve working with multiple threads without explicit locking as this has traditionally be the great pitfall of multithreading.

Peter Tillemans
  • 34,983
  • 11
  • 83
  • 114
0

Reading these answers here... A lot of them try to sound smarter than they really are imho (im mostly talking about Ruby related stuff as thats the one i'm most familiar with). In fact, JRuby is currently the only Ruby implementation that supports true concurrency. On JVM Ruby threads are mapped to OS native threads, without GIL interfering. So its totally correct to say that Ruby is not multithreaded. In 1.8.x Ruby is actually run inside one OS thread, and while you do have the fake feeling of concurrency with green threads, then in reality GIL will pretty much prevent you from having true concurrency. In Ruby 1.9 this changed a bit, as now a Ruby process can have many OS threads attached to it (plus the green threads), but again GIL will totally destroy the point and become the bottleneck.

In practice, from a regular webapp standpoint, it should not matter much if its single or multithreaded. The problem mostly arises on the server side anyhow and it mostly is a matter of scaling technique difference.

Tanel Suurhans
  • 1,632
  • 12
  • 11
  • "JRuby is currently the only Ruby implementation that supports true concurrency": Wrong, IronRuby and MacRuby do as well. "On JVM Ruby threads are mapped to OS native threads": Wrong, both Ruby implementations on the JVM (JRuby and XRuby) map Ruby threads to JVM thready, not native threads. (Mapping to native threads is pretty much impossible on the JVM without masive JNI C hackery.) "So its totally correct to say that Ruby is not multithreaded": Wrong. Just two sentences before this, you actually named a counterexample which invalidates your claim. – Jörg W Mittag Jun 21 '10 at 18:51
  • "In 1.8.x Ruby is actually run inside one OS thread": Wrong. Several implementations of Ruby 1.8 use multiple OS threads, for example Rubinius. "[...] green threads [...]": Wrong. There is nothing in Ruby that says you have to use green threads. In fact, there is nothing in Ruby which prescribes any sort of thread implementation, green, native or otherwise. The vast majority of Ruby 1.8 implementations (and Ruby implementations in general) choose not to use green threads, in fact, only a single one does. – Jörg W Mittag Jun 21 '10 at 18:55
  • "fake feeling of concurrency with green threads, then in reality GIL will pretty much prevent you from having true concurrency": This one doesn't even make sense. If you have only fake concurrency, then you don't *need* a GIL because there is nothing to protect against concurrent acess, because there *is no concurrency in the first place*. And in fact, the only Ruby implementation which has green threads *does not* have a GIL. The only two implementations which *do* have a GIL are YARV and Rubinius, both of which use native threads. – Jörg W Mittag Jun 21 '10 at 18:58
  • "In Ruby 1.9 this changed a bit": Wrong. The threading model in Ruby 1.9 is exactly the same as in Ruby 1.8. There are many changes in Ruby 1.9, like Fibers, Enumerators in the core library, Multilingualization, proc literals, unified argument semantics, but one thing that did *not* change are the threading semantics. – Jörg W Mittag Jun 21 '10 at 19:01
  • "In Ruby 1.9 [...], [...] now a Ruby process can have many OS threads attached to it (plus the green threads)" Wrong: the only Ruby implementation which *has* green threads is MRI. And yes, you can have both multiple C threads attached to a single MRI process as well as multiple Ruby threads. But, MRI is an implementation of Ruby 1.8, not Ruby 1.9. *No* implementation of Ruby 1.9 has green threads. – Jörg W Mittag Jun 21 '10 at 19:04
  • "[...] but again GIL will totally destroy the point and become the bottleneck." Wrong: MRI doesn't have a GIL. In fact, in MRI, multiple C threads can be running at the same time. Only one Ruby thread can be running but that doesn't have anything to do with a GIL, it is simply a side-effect of the scheduler implementation. Again, the scheduler is *incapable* of scheduling two threads at the same time, so there is no *need* to have GIL to protect the interpreter from multiple threads accessing internal resources at the same time, because there can *never be* multiple threads running anyway. – Jörg W Mittag Jun 21 '10 at 19:06
  • Guess Igvita have no clue about what they are doing and telling then. Go figure. http://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/ – Tanel Suurhans Jun 21 '10 at 20:25
  • The author claims in one paragraph that Ruby threads cannot run in parallel and explains in the next paragraph how JRuby runs Ruby threads in parallel. You don't even need to know Ruby to figure out that those two statements are contradictory and thus any article which contains both of those statements simply cannot be true. That's just basic logic: `A ∧ ¬A` simply can *never* be true. – Jörg W Mittag Jun 22 '10 at 00:06
  • Guess we didn't read the same article. What i saw was a clear separation of JRuby and MRI/YARV in that discussion. But it's probably not good enough for your nit-picking needs, so be it. P.S You do make valid points, but the way you make it beyond arrogant. – Tanel Suurhans Jun 22 '10 at 06:50
0

Yes Ruby and Python can handle multi-threading, but for many cases (web) is better to rely on the threads generated by the http requests from the client to the server. Even if you generate many threads on a same application to low the runtime cost or to handle many task at time, in a web application case that's usually too much time, no one will wait happily more than some fractions of a second for the response of your application in a single page, it's more wise to use AJAX (Asynchronous JavaScript And XML) techniques: make sure the design of your web shows up rapidly, and make an asynchronous insertion of those hard-coding things later.

That does not mean that multi-threading is useless for web! It's highly recommended to low the charge of your server if you want to run recursive-complicated-hardcore-applications (not for a website, I mean), but what that thing return must end in files or in databases, so then could be softly served by a http response.