{"id":18744014,"url":"https://github.com/at1as/parallelism","last_synced_at":"2026-04-14T14:32:10.895Z","repository":{"id":78922997,"uuid":"81525335","full_name":"at1as/parallelism","owner":"at1as","description":"An investigation into how several langagues handle parallelism and concurrency","archived":false,"fork":false,"pushed_at":"2017-02-13T05:37:50.000Z","size":9,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-20T06:37:20.828Z","etag":null,"topics":["concurrency","elixir","golang","parallelism","process","python","ruby","rust","threading"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/at1as.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-10T04:11:14.000Z","updated_at":"2017-02-10T04:11:41.000Z","dependencies_parsed_at":"2023-02-25T08:00:13.545Z","dependency_job_id":null,"html_url":"https://github.com/at1as/parallelism","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/at1as/parallelism","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/at1as%2Fparallelism","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/at1as%2Fparallelism/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/at1as%2Fparallelism/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/at1as%2Fparallelism/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/at1as","download_url":"https://codeload.github.com/at1as/parallelism/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/at1as%2Fparallelism/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31801283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T11:13:53.975Z","status":"ssl_error","status_checked_at":"2026-04-14T11:13:53.299Z","response_time":153,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","elixir","golang","parallelism","process","python","ruby","rust","threading"],"created_at":"2024-11-07T16:13:26.343Z","updated_at":"2026-04-14T14:32:10.887Z","avatar_url":"https://github.com/at1as.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Concurrency and Parallelism Implementations in Common Languages \n\n### Examples\n\nSee USAGE.md above for running examples\n\n\n### Description\n\n*Disclaimer*: This is a work in progress, and represents what I've learned so far. I'm sure I'm wrong about some of this. PRs or Comments welcome (and encouraged!!).\n\n\nDifferent languages handle concurrency and parallelism very differently. Although there are usually higher or lower level abstractions, or commonly used external dependencies, to mitigate a langague's weak points, some languages lend themselves more to certain types of operations.\n\nBelow, references to parallelism denote doing things at the exact same time (like breathing while running), while concurrency refers to rapidly switching between small chunks of work before the larger task is complete, but never truly doing more than one task at a time (like taking a step, then exhaling while not moving, and then taking another step while holding your breath). In the context of computers, true parallelism is when multiple processors or CPU cores are doing work at the same time, whereas concurrency takes place in one CPU core where programs may appear to do multiple things at once, but the in reality they're switching between tasks so rapidly it appears as though things are happening in parallel.\n\nRob Pike, the creator of Golang explains this concept wonderfully : https://www.youtube.com/watch?v=cN_DpYBzKso\n\n\nIt may also be worth understanding that an OS process is isolated from other processes and contains everything a program needs to run (including it's own memory). An OS thread, meanwhile, is meant to run within a process, and all threads share the memory of the process they are in. OS threads can utilize multiple CPU cores.\n\nNative threads are what programming languages use to refer to OS threads. Green Threads are usually language specific higher level abstractions on top of OS threads.\n\n\n\n## Ruby, Python\n\nPython and Ruby are languages built on C and have a Global Interpreter Lock (GIL) that ensures no two operations are occuring simultaneously. When threads are created in these languages, the GIL ensures that no two threads are actually running in parallel, instead allowing them to rapidly switch between each other.\n\nPart of the motivation for the GIL may be due to side effects of a Python program depending on C-level libraries without any knowledge of their internals. Jython and JRuby, Python and Ruby implementations built on top of Java instead of C, use OS threads that allow parallelism, but as a result break compatability with C extensions, and not all libraries are built with thread safety in mind (since the GIL ensures it in the implementations built on C).\n\nLangauges like these perform work sequentially by default, and doing things in asynchronously or in parallel is done by leveraring included libraries that distribute work across system processes. In Python the `multiprocessing` library will fork a new OS process, which can utilize multiple system cores. However, system processes are very heavy weight (can have hundreds of MB of overhead) and each CPU core can only do work for once process at a time. Typically, the a number of processes forked closely matches the number of CPU cores. The equivalent mechanism in Ruby is just to call `fork` and pass a block of work.\n\nPython and Ruby also have Threading libraries (`Thread` in Ruby and `Threading` in Python) that do work concurrently, but respect the GIL. \n\nRuby 1.9 moved away from green threads towards OS threads, however the GIL doesn't take advantage of parallelism of the system. Ruby 3.0 has a proposal out for the concept of `guilds`, which would separate code into separate guilds, each of which have a GIL that blocks with respect to its internals, but can run in parallel with other guilds. This would keep backwards compatability will existing code (since it would just be considered to exist in one guild).\n\n\n## Erlang, Elixir\n\nNote that while theyr'e very different, I use the terms Elixir and Erlang somewhat interchangably. Elixir is a light wrapper on top of Erlang, a language created by Ericsson for their massively parallel telephone systems. Elixir can natively call Erlang modules and use its tools.\n\nIn Erlang, each function usually runs in a separate process (a higher level Erlang language implementation of processes, not an OS process). This is done by using `spawn` or Elixir's `Task` module. Each process has its own memory heap and is completely isolated from the rest of the program. The functional and immutable nature of Erlang lends itself well to this type of design.\n\nProcesses are extremely lightweight and hundreds of thousands can run on a single machine. Erlang processes are inherintly parallel, performing operations at the same time across multiple CPU cores. There are constructs in the langauge for controlling whether operations are done eagerly, lazily, or with a maximum concurrency limit.\n\nCommunication is done by passing messages between processes (a function `call` is somewhat literal in this language). This makes Erlang programs easy to distribute across different physical servers (as the mechanism for distributing and send to/receiving from these isolated processes is the same). \n\nIt also allows for code to be how swappable (new processes will load the new code, and there is a mechansim for translating existing processes to the code).\n\n\nSee : http://elixir-lang.org/getting-started/processes.html\n\n\n## PHP\n\nPHP leverages OS processes in order to run. Each OS system process has a virtual address space that is completely isolated from other processes.\n\nThis is similar to Erlang, expect Erlang uses a higher level abstraction for processes that is much lighter on system resources. Maximum parallelism for PHP will be defined by the OS (`ulimit` is configurable settings for how many processes can run simultaneously on linux).\n\nPHP is commonly used in a LAMP stack that relies on a database on the back end in order transfer information between processes (since after a process dies, the contents of its memory no longer persist).\n\n\n\n## Golang\n\nGolang has also reimplimented lightweight processes on top of OS processes (for which hundreds of thousands can be spawned) and is not bound by a GIL. Golang differs from Erlang, however, in its shared memory.\n\nGolang functions can be made asynchronous by prepending the function call with the term `go`. Though concurrency can be handled several ways, it often uses a WaitGroup mechanism that increments and decrements a counter of running processes, and unblocks when all have completed (similar to the `join` syntax in Python or Ruby).\n\nGolang has a concept called `channels`, which are a mechansim through which different processes can send and receive from each other.\n\nIn Golang all memory is stored in the same heap, so garbage collection must be performed periodically, which can be a costly operation. Golang 1.8, however, improves the performance of the garbage collector dramatically.\n\n\n\n## Node JS\n\nIn JavaScript, code is run asynchronously by default. On the browser this was a useful mechanism to have many \"listeners\" for actions like users pressing a certain key, while still being able to perform other tasks while waiting.\n\nBy default, JavaScript is core bound, operating an event loop within a process. Not being truly parallel makes implementation of the language, as well as debugging, much easier (locking mechanisms are a frequent source of errors). When run on servers, however, making use of multiple cores is necessary, so it common to have Node with one main thread managing the sequence of events and several forked processes that will do more intensive actions.\n\nJavaScript employs mechanisms like `callbacks` and `promises` to handle control flow since the syntax is not completely sequential (for the circumstances in which one does which to wait for an action to complete before starting another. Like waiting for an HTTP response from a server before attempting to parse the body).\n\n\n### Java\n\nTODO\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fat1as%2Fparallelism","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fat1as%2Fparallelism","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fat1as%2Fparallelism/lists"}