When Go is discussed, you’ll often hear people throw around the acronym CSP. Often in the same breath it’s lauded as the reason for Go’s success, or a panacea for concurrent programming. It’s enough to make people who don’t know what CSP is begin to think that computer science had discovered some new technique that magically makes programming concurrent programs as simple as writing procedural ones. While CSP does make things easier, and programs more robust, it is unfortunately not a miracle. So what is it? What has everyone so excited?
CSP stands for “Communicating Sequential Processes,” which is both a technique and the name of the paper that introduced it. In 1978, Charles Antony Richard Hoare published the paper in the Association for Computing Machinery popularly referred to as ACM.
In this paper, Hoare suggests that input and output are two overlooked primitives of programming, particularly in concurrent code. At the time Hoare authored this paper, research was still being done on how to structure programs, but most of this efforts was being directed to techniques for sequential code, usage of the goto statement was being debated, and the object-oriented paradigm was beginning to take root. Concurrent operations weren’t being given much thought. Hoare set out to correct this, and thus his paper, and CSP, were born.
In the 1978 paper, CSP was only a simple programming language constructed solely to demonstrate the power of communicating sequential processes.
Hoare was deeply concerned that the techniques he was presenting did nothing to further the study of correctness of programs, and that the techniques many not be performant in a real language based on his own. Over the next six years, the idea of CSP was refined into a formal representation of something called process calculus in an effort to take the ideas of communicating sequential processes and actually begin to reason about program correctness. Process calculus is a way to mathematically model concurrent systems and also provides algebraic laws to perform transformations on these systems to analyze their various properties, e.g., efficiency and correctness. Although process calculi are an interesting topic in their own, And since the original paper on CSP and the language that evolved from it were largely the inspiration for Go’s concurrency model, it’s these we’ll focus on.
To support his assertion that inputs and outputs needed to be considered language primitives, Hoare’s CSP programming language contained primitives to model input and output, or communication, between processes correctly. Hoare applied the term process to any encapsulated portion of logic that required input to run and produced output other processes would consume. Hoare probably could have used the word “function” were it not for the debate on how to structure programs occurring in the community when he write his paper.
For communication between the processes, Hoare created input and output commands: ! for sending input into a process, and ? for reading output from a process. Each command had to specify either an output variable (in the case of reading a variable out of a process), or a destination ( in the case of sending input to a process). Sometimes these two should refer to the same thing, in which case the two processes would be said to correspond. In other words, output from one process would flow directly into the input of another process Below table shows a few examples from the paper.
|cardreaer?cardimage||From cardreader, read a card and assign it’s value(an array of characters) to the variable cardimage.|
|lineprinter!lineimage||To lineprinter, send the value of lineimage for printing.|
|X?(x, y)||From process named X, input a pair of values and assign them to x and y.|
|DIV!(3*a+b, 13)||To process DIV, output the two specified values.|
west?c → east!c]
|Read all the characters output by west, and output them one by one to east. The repetition terminates when the process west terminates.|
The similarities to Go’s channels are apparent. Notice how in the last example the output from west was sent to a variable c and the input to east was received from the same variable. These two processes correspond. In Hoare’s first paper on CSP, processes could only communicate via named sources and destination. He acknowledged that this would cause issues with embedding code as a library, as consumers of the code would have to know the names of the inputs and outputs. He casually mentioned the possibility of registering what he called “port names“, in which names could be declared in the head of the parallel command, something we would probably recognize as named parameters and named return values.
The language also utilized a so-called guarded command, which Edgar Dijkstra had introduced in a previous paper written in 1974, “Guarded commands, nondeterminacy and formal derivation of programs“. A guarded command is simply a statement with a left– and righthand side by a →. The lefthand side served as a conditional, or guard for the righthand side in that if the lefthand side was false or, in the case of a command, returned false or had exited, the righthand side would never be executed. Combining these with Hoare’s I/O commands laid the foundation for Hoare’s communicating processes, and this Go’s channels.
Using these primitives, Hoare walked through several examples and demonstrated how a language with first-class support for modeling communication makes solving problems simpler and easier to comprehend. Some of the notation he uses is a little terse, but the problems he presents have extraordinary clear solutions. Similar solutions in Go are a bit longer, but also carry with them this clarity.
History has judged Hoare’s suggestion to be correct, it’s interesting to note that before Go was released, few languages have really brought support for these primitives into the language. most popular favor sharing and synchronizing access to the memory to CSP’s message-passing style. There are exceptions, but unfortunately these are confined to languages that haven’t seen wide adoption. Go is one of the first to incorporate principles from CSP in it’s core, and bring this style of concurrent programming to the masses. It success has led other languages to attempt to add these primitives as well.
Memory access synchronization isn’t inherently bad. Sometimes sharing memory is appropriate in certain situations, even in Go. However, the shared memory model can be difficult to utilize correctly-especially in large complicated programs. It’s for this reason that concurrency is considered on of Go’s strengths. It has been built from the start with principles from CSP in mind and therefore it is easy to read, write, and reason about.
your comments are appreciated and if you wants to see your articles on this platform then please shoot a mail at this address firstname.lastname@example.org
Thanks for reading