 Today, we're going to talk about concurrency. We discussed a few couple of topics we could talk about together last spring. And it went all over the place. There was a bit of home automation there, a bit of augmented reality with Ruby. And then Eleanor proposed concurrency. And it turns out it's an excellent topic. You can just speak for years about that. So, yeah, concurrency matters. Basically, the reason that is most cited is the fact that hardware has changed. Somewhere around 2005, people stopped making processors faster, mostly because heat evacuation became a bit of a problem if you had higher clock rates, as far as I understand. And so people started, manufacturers started to add multiple CPUs and multiple cores per chip. One core executes one instruction at a time. And so you can have several on a chip. And in fact, at this point, the story becomes a bit more complex because since processors are quite fast, the bottleneck becomes access to memory. And so you've got caches on top of your processors and those caches can be shared or not between cores and there can be physical connections or not between the cores on one chip. And you've got systems where all the cores are equivalent, what you call symmetric multi-processing. And then you've got more scalable systems where non-uniform memory access where processors have their own memory banks, which makes it easier to work together. Nowadays, real supercomputers have many, many cores. Those are numbers I plucked out of thin air, like Intel, AMD and Tyler chips that are on the market. So you kind of understand that as a programmer you cannot longer ignore this. You can obviously keep on programming sequentially, but that's okay for a system with two cores. But if you've got a system with a hundred cores, you're obviously missing out if you're not aware of the whole concurrency aspect. It's not straightforward because of the complexity I was talking about. There's some synchronization needed between processor caches. There are some overheads to concurrency. So your program's performance won't scale linearly with the number of processors you've got. So it's a very complex issue and you basically have to be very aware of it. But there's another aspect as well to it. Our world is a concurrent place. Many, many things happen at one. Your brain works concurrently. When you're driving on the road, you're aware of all the things going on. And you can talk on your phone and walk at the same time. So basically, this is a way of functioning that is kind of natural to us. And well, it can also be thinking about those things, can also help you make your design better, decouple independent tasks, work out your data in a way that is decoupleable. Support parallel execution, scalability, obviously. But the problem is when we as developers develop a concurrent program, this is basically what we picture. Little soldiers marching in a row next to each other. You know, 12 threads. Okay, we've got 12 cores. That'll work. Well, obviously the situation is a bit different. It's the best metaphor I've found is sending a stream of cars on a busy road. So sometimes your cars will drive next to each other. But sometimes one will park and other cars will pass it. And so it's something very difficult to picture. It turns out naturally Ruby doesn't really make it too easy for you to handle this complexity. And so we've decided to look at other languages and other, how do you say, paradigms. Which was very interesting because it turns out that many of those things you can also reuse or program in Ruby. And there are reams of what's called concurrency-oriented languages out there. But we've picked a few that we thought illustrated some concepts. Our language functions with actors. Go with concurrent sequential processing. Closure, very hot in the Ruby community right now apparently. With software transactional memory. And I come for its nice use of co-expressions and coroutines. Yeah, and when we came up with the proposal, we sort of made this mad idea that we're going to teach you everything possible about concurrency in 45 minutes. And everybody in this room who thinks concurrency probably automatically leaps to the multi-processing thing. But actually all concurrency relies on some basic fundamental bits of math. We write functions in our programs. We put data in. We get an answer out. That's a subset of something called a co-routine. A co-routine you can stop anywhere and you can then resume it and start it up again from that point. And we do this all the time actually in Ruby without even thinking about it. Every time you do a block yield, you're doing a co-routine. It's a dumb co-routine but it is a co-routine. Now I'm just going to skip back a few slides here assuming that I can get this thing to do what I want it to do. Because I'm lousy with technology unfortunately. To here. Now this, as Elise says, this is how many people view concurrency when you're writing code. And I think there's something fascinating in this picture. Him and him. Everybody else there is marching forward in fine Korean style to take over the world. And these two guys, they're petrified of missing their step. They know they're going to screw it up and they're at the front. They go down. Everyone goes down. And we build our concurrent systems like that most of the time. We build them so fragile because we don't think of anything other than get as many tasks onto processes as possible. I'm not going to talk about that at all today really. We really don't give a damn about whether we're using the hardware efficiently. That isn't really the purpose of this talk at all. So co-routines. Basically a co-routine, as I say, is a function that you can suspend and then resume from the point where you suspended it. And in its simple form, that's a co-expression, it returns a value. In the more general form a co-routine can then invoke another function that invokes another function and they can all do this to each other. So you can have these rings which you haven't got a practical useful, but it's quite fascinating. And I'm going to actually go off on a strange riff here. I'm stepping back into the 1980s because my second favourite programming language in the world is from the 1980s. This was the original agile language, ICON. This is the language that, back when I was an undergrad doing my physics degree, I needed a language that I could write a fluid dynamic simulation in on my 640K Intel. Actually it wasn't Intel, it was NECV30 for that extra 5% processing power. And I couldn't find enough to share a language I could use. You know, C-compilers were like 200, 300 quid at the time. I couldn't afford those. And I found this lovely language lurking online. And ICON is basically, it's a strange cross between our goal, it looks like a traditional procedural program, and prologue because it's got backtracking and goal direction. It solves problems for you after you describe how the data works. Very weird language. But anyway, ICON is particularly good at co-expressions because it's a generator-oriented language. Generates values all over the place, infinite sequences, whatever. And in recent years, Ruby's developed fairly reasonable generator support. It used to have quite unpleasant generator support in 1.6. The generator line was lousy. So I'm going to show you a bit of ICON code. As you can see, this is really old-fashioned code structurally. There's no objects in here, this is not an object-oriented language. But it's got a few interesting things going on. Up here, these create statements, you just give those a function, it turns them into a co-routine. That one at the top, that little slash there, dangling off the back of that function call. That says, I only want the first 10 results. After that, kill this co-routine. I couldn't give a toss about it. That line there, while right, that's actually invoking those three co-routines above it, in parallel with each other. Now, it's not parallelized into the runtime, the runtime sequential. It's a very old language implementation, everything. But conceptually, those three things march in step with each other, just like those Korean soldiers. They could never get out of sequence. It's lazily evaluating all of that as well. It's generating those results on the fly as it needs them. I wanted to play with this a little bit to show off code expressions. I'm going to show you how to do this in movie as well. This isn't completely pointless. The really nice thing down here, you should recognize this basic pattern of code. Suspending in ICON is just the same as doing a yield. It's like slightly richer semantics underlying it. Those are just infinite loops that generate series. We have something in Ruby that can do code expressions very nicely. Fibers. I don't know, does anybody here play with fibers? That's a lot more people than I would have thought actually. Fibers are kind of fun. They're just little code expressions. The one thing about them that narks me is the fact that they're bound to a thread. You can't move them to another thread. It's very annoying. Conceptually annoying. I don't have a need to do it. I hate things that won't let me do something. It's just a point of principle. Fibers are basically code expressions. They're scheduled cooperatively. When they yield, they yield to or something else. Nothing schedules them for themselves. We will see something similar to this later in the talk that does get automatically scheduled, that is really neat. I know the base is in 1.9 for enumerators. This is how you do the same piece of code in Ruby, as was in Icon. For anybody who wants to know what this is actually doing, this is doing arithmetic calculation of squares and cubes. I wanted something that filled enough space on the screen to make it worth actually putting on there. Then I suddenly discovered it's quite amusing figuring out how to work out arithmetic in cubes. I have a strange turn of mind. Fibers are objects which is a nice step forward on the Icon example. You can save them, you can pass them around. They're first-class values because they're objects. This is doing exactly the same thing. They're yielding off values. Resume is exactly the same as the code routine invocation in the previous piece code. The one thing that's a little odd, of course, is in Ruby, I have no way of doing that cut operation on a Fiber. I can't just say I'm only interested in the first 10 results. I have to actually manually take 10 results and then stop doing it. There's a lot of technical reasons under the hood for why Icon can do that, which I'm not going to go into. Now, this is a code routine. Wait a sec. Oh, yeah, I did it in the wrong order there. This is a code routine. This is slightly more interesting because these two things are transferring control between each other. In a sense, in the former example, the piece of code acts as a server for your software and your code is actually being a client to it, asking for value from it. Whereas this is a pair of peers that are communicating, in this case, to do a simple login thing. This is trivial stuff. I can't actually think of anything to say about this code because it's so self-evident once you... It's actually vaguely inspired by something by Zetro. He did a blog post on Lua with that. He lurks everywhere. This is doing that piece of code in Icon. Now, the one thing that's cool with the Icon version is there is fundamentally less code to do it. That's because Icon is a language in which code routines are first-class values. They are a fundamental part of language syntax. Whereas here, that's not the case. I mean, we have to go through a lot of work. However, we can still get pretty close to doing the same sort of thing because we're here, things are popping backwards and forwards and invoking each other. We've got the same thing going on here. This is fully symmetric code routine. That's step one of concurrency. How to have two things that are conceptually parallel. Not parallel in time, but parallel logically. I'm going to pass back over to Elise who's going to talk to us about processes, which is the next step up. That's as pathetic as I'm going to get today. Yes, obviously, you all know the basic concurrency tools. We have concurrency classes we have in Ruby, but which correspond to the kernel, the operating systems, things we need to use for concurrency. The first one is processes. When you schedule anything, whether it be threads or processes, you basically don't get to choose what's happening underneath. Your program is like a thin layer on top of language VM, which then maybe schedule threads, which use the threads, which are then scheduled usually by the kernel itself or by the OS itself. I wanted to show this slide because I didn't do computer science. I didn't study computer science. In fact, when you're using computers and learning on the job, you think that processes are the unit of execution, but while they're not, the unit of execution is the thread. So processes are basically the address space shared by several threads. In this case, we could imagine, instead of the process, the Ruby VM, and it can have several threads running in it. Eleanor talked about coroutines. Coroutines use cooperative scheduling. This means when fibers run, for instance, they yield control to each other. So the scheduling is basically done within the threads by the fibers themselves. Most of the thread scheduling is preemptive. There's a scheduler actually saying, look, yield control to the next thread. So that's what the operating system usually does. This is, again, a bit what I explained before, is that when you send a series of threads onto, for instance, a dual core system, you don't know what's going to happen. And, well, a brief overlook of the difference between processes and threads, which is mainly that processes are that heavier and don't share states. Usually, while threads within one process do share states. Now, one thing we found is that, indeed, processes are a bit heavier to spawn than threads. Because of all the overhead that goes with it, but the difference is not that important. And, in fact, this is due to a particularity in unique systems at any rate, is that when you fork a child from a parent, most of the process is actually copied which presents much less overhead than just spawning one. And this is actually the origin of what you might know as copy-on-write. Copy-on-write is used in Ruby Enterprise. And what it does is it allows Ruby to exploit this mechanism. So several threads spawned from the same parent will actually use the same memory space until they write their own things. And then the memory is actually copied. That's why it's called copy-on-write. I'll talk about pipes then. One of the things about having processes is they then have to talk to each other. So, Unix and Windows, and quite a few other operating systems as well, give you a concept of pipes. Basically, a bit bucket. You chuck data in, it comes out. Because they go between processes, this means on most systems you have context switches, so I dump my data out, I get a context switch, I get some data in another process. There's some interesting stuff been done in recent years. Linux gained something called zero copy pipes where, effectively, they live in the same address space as the two processes they connect, so there's no context switch. There's some weird stuff that goes on in some BSDs as well that allows you to, yet again, get data from one process into another without having to go into understanding shared memory, which is a nightmare. And then, of course, there's named pipes, which are really lovely, because they're just basically a point in the file system. And unlike normal pipes, which are just two endpoints, named pipes are multi-way, so you then have to lock them when you write to them. But that actually allows you to multiplex data across lots of processes. These concepts, again, with threads and quite a lot of other ways of doing concurrency, because at the end of the day, we keep inventing the same things. It's just we keep pushing them into different granularities to see what we're actually doing. And here's an example of how to actually do a fork in Ruby. So I'll walk through it, because it's fairly simple. The thing about a fork is, in both of the processes, that's created under one that's the parent, they both return from the same fork call. The state of the program is more or less identical at that point. There are a lot of complexities to do with threads, native threads, that mean that the state of the two processes isn't the same. You only have one thread of execution in a child. But you get the same pipes and the same file descriptors and everything shared in both. The only difference is that when you come out of that fork call, you either get a zero if you're in the child, or you get an actual process ID number if you're in the parent. What's going on here is you've got a pair of pipes that you know connects these two processes, and it's traditional to shut one pipe in the child for reading and the same pipe for writing in the parent and vice versa. And then they're two one-way things. There's no actual reason why you have to do that. It just makes for saying the programs. You can keep them both open by direction if you want and live with the consequences of trying to think about that. And then it's traditional also for most forking processes that the parent will end up waiting on the child process at some point. So that's all covered in there. Yeah. I find it's a lot nicer to wrap up the whole fork thing inside an exception, so you can actually have an exception capture that says, oh yeah, I'm the parent thread, I'm the child thread. And then semantically it's very clear to read the code because otherwise people go, why does it matter if it's one or zero? Very good reason. Now we've got some numbers here, and these are really ludicrous, because try finding benchmarks for thread creation and process creation on the internet. And apart from strange flame wars on the free BSD mailing lists about thing. But this is great. This set of benchmarks is from probably about 1980's. So this would be Linux 2.2 kernel, which is really, really lousy with how it does threads. A thread is just a process that doesn't have a name or something like that. Windows NT, that's probably NT4, with which I'm fortunately far too familiar. And the thing that this is, I want to describe here, this is a P200 MMX. This is a very, very slow piece of care. I don't even own a machine that slow anymore. At least not little power on. But notice, all of those times down the side, those are in milliseconds. To fork a process on a really old Linux distribution, on a really slow machine, take six milliseconds. Every time somebody tells you forking is expensive, it is not expensive. It is the fundamental basic units of concurrency on a Unix box. It is not expensive. Even on Windows that has to create a whole process from scratch, it is not expensive to create a process. Just relatively expensive. But you'll also notice, it's also true, threads are bloody fast in comparison. About an order and a half of magnitude. And getting better with modern implementations. It's got numbers. I just can't resist things that actually have real data. It's so rare to find it on this stuff. The thing about any kind of concurrent programming, whether you're looking to do parallel code across multiple cores, or you literally just want logical parallelism, is you must do everything possible to avoid every sharing state. There are lots of mechanisms that will allow you to, and nearly all of them is a poison chalice. Because they look very simple when you're using one or two or three things talking to each other. But when you've got two or three hundred things talking to each other, it is almost impossible to reason about the actual data that comes out of testing what's going on. So there is a lot of non-determinism. People go, computers are not non-deterministic. They can't possibly be. They've got a finite clock pulse and everything. What quantum mechanics shouldn't be non-deterministic? Should it? It's got a finite clock pulse. The point is the moment you have things interacting, the deterministic behavior goes out of a window. So it is, do not share state. Also, when you've got anything that involves automatic scheduling, you have the question of whether or not that scheduling is fair. So we're not going to go into too much detail about that, because actually that's a, how do you perform and tune concurrent code thing? And I'd really, yeah, not today. But also, I mean, the main thing you have to deal with if you are going to share state is race conditions. Two things being able to get at the same thing at the same time. Each believes they have an authoritative view and each put crap in there. It's not crap to them. It's based on very good actions. They've done everything correctly algorithmically. But the point is, neither of them is aware that they're crapping in somebody else's backyard. And they should be. So there are two ways around that. And we're going to cover both of them a bit during this talk. One is looking and the other is transactional memory. And I know that most people think transactional memory is more sexy, but honestly it isn't. It's just a database. It really is. Unix gives you a really nice thing for signaling between processes. So you can start to get some synchronization going, some concurrency that actually makes a bit of sense. And that's semaphores. And I'm, I've stuck this bit of code that I'm about to show you in, because I love sticking in anything that's got RubyDL in it. It's because nobody uses RubyDL enough. You can't do this from straight Ruby. The one thing you cannot, there are about three different things on a Unix box that you can't grab from straight Ruby and turn into an IO object. And semaphores, oddly, is one of them, even though it looks under the hood like it should. Well, you can do mutexes, I guess. That's so boring. Sorry, I'm opinionated like this. This is a very simple example. Basically, it just loads up libc and it decides to load in the appropriate physics calls for playing with semaphores. And these two processes ping-pong, ping-pong, ping-pong. One gets a lock through the semaphore and then it releases it and you find out what the time is. As I said, I mostly like it because it's a RubyDL example. I think we've lost the ability to... Oh, shit. Oh, dear. You're too far. Are you supposed to say that on here, dear? Went that way? No, it doesn't want to skip to the next one. Excuse us while we have technical difficulties. I bet you that damn thing's got a lurking time of transition. All right. I mean, complexity. As I say, there's a lot of complexity in the kind of code you write on a Unix box anyway. And people have come up with some fun sort of tools that you should go off and you should read about. And at the end of the presentation, I'll give you a reference for where you should go and read about it. Fire locking, shared memory, message queues, which everybody thinks are sexy, and transactional data stores, which are basically just your database server. So threads. Be gentle. So, yeah, let's talk about... You've all heard of the global interpreter lock, which is on MRI. It will keep threads from running parallel. So there is a lock. There is a kind of mutex which will ensure that only one thread is running at any one time. Now, Rubinus, I heard in Evan's presentation, is working on removing that lock. So soon the only Ruby VM that will still have that thing is the original Ruby, MRI Ruby. JRuby doesn't have it. MacRuby doesn't have it. I run Ruby either, I think. So, yeah, only one thread executes at a time, and there is actually a timer thread in the VM which will interrupt the threads so that every 10 microseconds on Linux, another thread gets to run if there's more than one at any rate. I'm going to be geeky here and just interject. The reason why it's 10 microseconds for Linux and 10 milliseconds for Windows, and that's because Linux these days uses a microsecond context switch. It never used to. It used to have a millisecond context switch, but now it's got a microsecond. Whereas Windows still has a millisecond context switch, which, if you think about it, an awful lot of people don't realize a lot of the performance that you lose when you write massive multi-process system isn't actually anything to do with those processes themselves. It's actually a limitation of having too slow a context switch clock because that's actually what dominates most performance in multi-process systems. So, God, I'm geeky. So, even more than processes, threads have... Well, threads in the same processes share states, so even more than with processes, you've got the problem that you have when you have a mutable shared state, and there are several ways to address this, which is like mutex's monitors or sync in Ruby, and condition variables, which allows you a little bit more logic in transferring the lock. Now, the problem is that it's really, really difficult, especially when you've got lots of threads next to each other to avoid problems like deadlocks, which is like one process holds a lock on one resource, and the other process holds a lock on another resource, and the first process wants that other resource, and the second process wants the resource of the other process, threads. And so you get a situation where none of the threads progress anymore. And when you try to actually solve that, you can land in the situation of live locks where threads release their locks, but in such a way that there's like an infinite loop between those threads, and none of the threads gets to progress anymore. Here's an example by... I apologize for this. I wanted to show an example using thread groups, and unfortunately to use thread groups, I then had to come up with something and some threads they were going to manage, and then I had to come up with a reason for why the threads exist, and I always end up writing too much code, and I apologize. A thread group basically is this little unit of space that you can bung a whole pile of threads into, and a thread can only ever be in one thread group. And as far as I can tell from reading the sources, moving from one thread group to another is an atomic action. This is particularly useful if you want to avoid all kinds of horrible concurrency problems. So, over here, basically I have a horrible habit also of injecting code into core classes when I'm doing examples, because it saves a lot of boilerplate. And I happen to know later on that I'm going to be wanting to get at some data that's within each individual thread in a group, and that I'm going to want to sometimes do something on everything but the thread that's the current calling one, so I've put in a couple of things for doing that. Down here, the other thing I wanted to show off, I wanted to show off thread variables, because nobody really seems to talk about thread variables either. Every thread has a whole bunch of variables that basically is a hash, and you can stick things in values in that hash, and then you can do stuff with it. And what that... You weren't supposed to do that. And basically, this is quite... This looks intimidating, especially when you see the 12-point follow-on slide. The next page... We'll come back in a second. Well, basically, what this is doing, this is creating a chat client, and I decided I was going to decouple transmission from receiving. So you've got to transmit a thread for every connected client, and you've got to receive a thread for every connected client, and it's all tied together through queues, which are nice atomic entities that you get when you require thread. And you put an item on a queue, and somebody else takes the item off the queue, and there is no way for any thread crapping to happen in the middle of that. I do apologise for my language. Some of this stuff I just can't really think of how to describe. So... And I spend entirely too long in the wrong kind of company. That's not skipping again. It has particular slides. It's obviously very keen on. So... I'm actually going to skip over the following page, which shows how to use all of those, because that's actually designed for you to look at offline. And I'm going to talk about the nice little twist on threading that MacRuby gives you, because MacRuby fully embraces MacOS 10. So it actually does all of its threads on top of Grand Central Dispatch, which works out how to schedule them for you. And this actually means that when you're programming in MacRuby on a Mac, your threads act exactly the same way as if you're programming in Objective C on a Mac. It's a genuinely native thread implementation, which is kind of sexy. And it's got a few ways of handling new stability and atomic locking. And now I'm going to pass back to somebody who actually does know Clojure. Yeah, so I had a lot of fun for this presentation playing with different languages. It had been a while, so... It's like a breath of fresh air. I really recommend it. So, yeah, Clojure actually has several mechanisms for concurrency. The one I'm going to talk about mainly is software transactional memory, which basically allows you to have transactions. I'll get to it in a minute. Then you have agents, which allow you to do asynchronous message passing. And then you have vars, which allow you to have states within a thread. So that means it's not shared with others, so you avoid all kinds of troubles. And basically by default, threads are cleanly separated. The state is not shared, or whatever state there is anyway. So, yeah, check out... If you want to find out experiments with concurrency, you can check out this blog post series by Tim Bray. Pretty interesting. This is not very visible. That's a kind of a shame. So, I made a very simple example with a ref, which is actually a variable that falls under this transactional memory. And... I mean, we can say, how would you... Show the next slide, because the next slide's got pretty colors as well. Well, not much better. Unfortunately, the colors are just as bad, but this is the same thing in moving. Yeah, that's the cool thing. I don't know if I forgot to look up his real name, but he's a big fan of the technology on Twitter. Made this gem called Clojure Gem, which allows you from JRuby to access this software transactional memory mechanism. And so, the thing you cannot see here is perfectly reproduced there, with Ruby threads. And it's a bank account example where the balance is basically the one you do a transaction on, so you make sure that any incoming transfer is actually executed and there's no risk conditions. If you were doing it with threads without any locking, you could have one coming in with 40 and another with 60, and the output of the balance could be 40, 60, 100. And so that's in the terminism. So, software transactional memory is also possible with JRuby. Oops, wrong one. This is my personal bugbear in the Ruby world. In new models, we use them all the time, and they are in most instances naturally concurrent. This is because, effectively, every collection in Ruby is a first-class value. We can treat it as a whole. When you do an each, you are extracting things from this group. But if you do a map conceptually, you are treating each item in parallel. And there isn't exactly a lot of support for that in MRI under the hood, which is a pity, because it would speed a lot of stuff up. So I'm not going to talk too much about the previous bit, but map-reduce is how you get round this idea of manipulating collections. Map-reduce just says, I will do this mapping operation across everything in parallel, and then I will spend the time doing this boring sequential commutative operation to stick it all back together as a value that you want to understand. And here is an example of... No, I'm lost for whether or not this is really a good example, but anyway, it seemed like a good idea at the time. Map-reduce is a two-phase operation. It has a concurrent bit. It has a sequential bit. This concurrent first example is a really bad one, because actually, protest does have a side effect. The order in which things come out doesn't actually matter in many cases when you're reading a screen, but in theory, whenever you do something within each that doesn't return any value out of that and doesn't change the state of your program, it just does something inside there, that's a concurrent operation. Those can all run in parallel. Likewise, every time you do a map, that should fundamentally be a parallel operation. Sequential operations are things like inject. Inject is fundamentally a sequential operation. That's the reduced half of map-reduce. This each up here, it affects external state. Yet again, that is the sequential operation, the order in which that each happens does matter. It may not actually be what you thought it was going to be when you did it, but it does matter. Perhaps it's a range thing. No. I have this horrible effect on technology. Next one. Next one down. This example is actually using a gem called parallel, which will quite happily allow you to set a number of processes or threads with which to process an innumerable operation. You can actually get that benefit of being able to do these things actually across multiple cores that you don't currently get with MRI. It doesn't really change the patterns of code you write, so it's quite nice. Now I have to get into some theory, I'm afraid. Process calculator. Who's ever heard of communicating sequential processes? That's even less than used fibres. The rest of you are complete disgrace. This is a whole branch of math, process calculator, a branch of math to do with independent entities talking to each other. Off the back of it comes communicating sequential processes, which is these processes each do a sequential thing and they talk. It's the basis behind the worst programming language in history and the coolest processor ever made. The worst programming language being OCam, which is disgusting, and the best processor ever made, of course, being the inmost transputer, which rocks. I'm really very... Yeah. But anyway, strange interests. Anyway, basically, we had a bit of a discussion just writing the slides about whether or not process calculator require synchronous or asynchronous communication. In every implementation I've ever played within the real world, they allow both. And effectively, everything that goes... They have channels that connect things and everything that goes over the channel is an atomic operation. And I'm going to talk a bit about my current favourite obsession and what I spent most of the year actually working on, which is Go. Anybody here a Google Go programmer? There's just a number of Google Go programmes I've met in the world. It's great. I turned up to this Google event in London. Google were hosting it. I was the only person in the room who actually could program in Go. It was sad. Okay, it's subtly compiled. It's a systems language. It hasn't got classes. It is object-oriented. If you looked at Natalie's session yesterday, it does a very good kind of object. And it's really... It's got really good concurrency and garbage collection, God send. And this is a really simple example. This is how you write a clock post-generator. The main structural things that are interesting are, firstly, this type has a couple of channels. One for integers and the other for Booleans. And you can pump things along those channels independently. You'll also notice that there's some strange malarkey going on with the function specification over here. That's because that's how you define methods on data types. And it's a bit like clue in that you can put methods on data types rather than on objects. That's kind of nice. The other interesting thing is this thing over here, a select. How many people have ever written Unix-Cons programs? Have you used select? It's an oxymoron, isn't it? Everybody does. It's the most efficient way to do it. Basically, that will just quite happily sit there, whichever one of the cases gets satisfied is the one it will respond to. So you can basically set up hundreds of channels if you really want to, and then just respond to whichever one comes in next. So it breaks up. And then over here, there's this go-funk thing. You'll notice this is a bloody big closure here in the middle of this. And basically, that's how you spawn off concomit processes, and they go off and they do stuff. And it just ticks, tick-tock, tick-tock, tick-tock, tick-tock. And I was going to actually show an example in Ruby, but this was sort of like the very last set of slides we stuck in, sort of like 10 minutes before we came in here. And I've written too much code this week already, and just a Ruby example is going to work. So I'm setting your homework, which is to write a signal generator in Ruby. And it's very easy to do, because all of the things that are in that piece of go-code are in these thread and socket example that I lost over because it's a big chunk of code. But yes, Ruby basically will natively do CSP, because all you have to do is import thread and you get atomic queues. And you've got thread variables, which means you combine things to individual threads, like queues, and then you can address those queues if they're in thread groups in really clever ways. And I wish I'd thought that Ruby could do this a long time ago, rather than it just suddenly occurring to me the other morning in an epiphany. And now I'm going to pass back to Elise, because I do not want to talk about actors. I think it's too easy for Ellie to talk about actors. The concept of actors is actually quite simple. You've got separate actors, and they can pass message to each other asynchronously. So another metaphor you could think of is person, people in different rooms sending each other email, and then some of them will actually read their email and act on it. So they have no shared state at all. And one language that is basically nearly based on this model is Erlang. Erlang has very lightweight green processes, which are the actors. So on top of the VM, you've got these very light processes. You can spawn really a ton in very little time. And the VM underneath is very efficient as well. It's been SMP enabled since 2007 or something, and this means that it has several schedules, which can make sure that underneath there are enough threads being spawned. It's a functional language. Yeah, it has a very nice upgrade capability, hot code loading, but that's not really important here. And it's fault tolerant. So I'm sorry once again. Not very contrasted. I'm sorry. For those of you who'd like to thank the authors of the really bad colours, GitHub. Maybe you could come and help. No, no, no. Apple, wait a second, let's do that. All right, Apple, Option, Control, 8. What is this, a Windows box? I think it might need to be enabled, yes. I need you to say all these slides will be online by the end of the day, so you can go and read the bits that you can't read. I'm so really sorry about this. It's something you learn, it's a basics to have contrast, but yeah, apparently, okay. So basically what we have here is a MapReduce, and this MapReduce uses a library called Pealists, which is basically more or less the same thing than I showed before with Sparrow, and it allows you to spawn several threads, sorry, green processes in case of Erlang, based on a list, and then you can gather those and do a Reduce operation. Now, in Rubinius, there's actually something called Actors as well, which is, I think, based on Erlang, and it's implemented as Ruby threads with a mailbox. Yes, again, another example with Actors, and basically it has more or less the same syntax as the Erlang, and there was actually also VM Actors, which allows you to communicate between several processes, several VMs, but last time I tried to play with those, they didn't really work, so I guess they're a bit discontinued right now, but Rubinius Actors do the same thing as the Erlang thing. Revactor, I'm not going to go into too much details here, because Tony Arsieri is going to talk about Revactor and Rhea, his language, I think it's next slot or the slot after. Revactor also has Erlang-like semantics, but it works on one thread, it's cooperative scheduling, and it's basically very good for networking programming, because it uses an event loop, so it's basically not really the same use case as Erlang would be with real parallel processing, but it's a nice event loop for network programming. Now to Ali back. Yeah, promises and futures are a really clever way of saying lazy evaluation, or more to the point, a way of giving you a language construct that actually makes lazy evaluation obvious you're doing it. Basically, with a promise, you just spawn off a piece of code that goes off and calculates something now, and when you ask for that value back, if it hasn't finished calculating it, you'll just block until that value comes out, because it's promised it will give you it. At some point in the future, I want to know the answer to this, please keep this environment this state, and when I ask you for it, then go off and calculate it. Of the two, a promise is the one that's actually useful if you're talking about multi-core. Conceptually, they're identical. At the point of delivery, they give you an answer. This is an example of Ruby futures using mentalguyslazyrb.gem. Yeah, again, that's readable in the online sites. There are three things we didn't cover, we've already run out of time. Tuple Spaces, which are a great way of sticking data out. They're things like Memcache. Memcache is effectively an example of a tuple space. Event-driven I.O., because I can go on for absolute hours about kernel-based eventing in Unix machines, and Petri Nets, which are really their alternative to process calculating. They're another mathematical formulation for doing control, but I think they came out of business and control theory or something. The main point I think we want to get across is we keep reinventing the same wheels. We just make the granularity of the wheel smaller every time we do it. We fit it into a smaller place. We take away a lot of the safety we might have had with the previous one to get more performance, and that's really where we've been going. Beware of a multiple-state. Use sane ways of handling your concurrency, and everything you think you need another language for, you can do in Ruby. That may not mean you want to do it in a movie, but you can, and I think it's interesting that you can. I think that's a good hack in its own right. Above all, have fun, and here are some useful resources, including the most important book that you could ever probably own, which is Advanced Programming in the Unix Environment, which will teach you everything you need to know about processing threads and doing weird stuff with system calls, and that's how I actually got into doing standing up and talking about this crud, because I spent too long reading books like that. Also, that bottom link there for the C10K, that is the most important concurrency-related post that's ever gone on the internet. That's the famous 10,000 connections in seed problem. How do you have 10,000 connections in a seed program? It changes the way you view concurrency completely reading that. We can be found at those appropriate places. We're both on Twitter, we both have websites, and we will be sticking these slides up as soon as we're out of here. Thank you very much for your time, and thank you.