@@ -4318,6 +4318,152 @@ the same function, so our binary is a little bit larger.
4318
4318
4319
4319
# Tasks
4320
4320
4321
+ Concurrency and parallelism are topics that are of increasing interest to a
4322
+ broad subsection of software developers. Modern computers are often multi-core,
4323
+ to the point that even embedded devices like cell phones have more than one
4324
+ processor. Rust's semantics lend themselves very nicely to solving a number of
4325
+ issues that programmers have with concurrency. Many concurrency errors that are
4326
+ runtime errors in other languages are compile-time errors in Rust.
4327
+
4328
+ Rust's concurrency primitive is called a ** task** . Tasks are lightweight, and
4329
+ do not share memory in an unsafe manner, preferring message passing to
4330
+ communicate. It's worth noting that tasks are implemented as a library, and
4331
+ not part of the language. This means that in the future, other concurrency
4332
+ libraries can be written for Rust to help in specific scenarios. Here's an
4333
+ example of creating a task:
4334
+
4335
+ ``` {rust}
4336
+ spawn(proc() {
4337
+ println!("Hello from a task!");
4338
+ });
4339
+ ```
4340
+
4341
+ The ` spawn ` function takes a proc as an argument, and runs that proc in a new
4342
+ task. A proc takes ownership of its entire environment, and so any variables
4343
+ that you use inside the proc will not be usable afterward:
4344
+
4345
+ ``` {rust,ignore}
4346
+ let mut x = vec![1i, 2i, 3i];
4347
+
4348
+ spawn(proc() {
4349
+ println!("The value of x[0] is: {}", x[0]);
4350
+ });
4351
+
4352
+ println!("The value of x[0] is: {}", x[0]); // error: use of moved value: `x`
4353
+ ```
4354
+
4355
+ ` x ` is now owned by the proc, and so we can't use it anymore. Many other
4356
+ languages would let us do this, but it's not safe to do so. Rust's type system
4357
+ catches the error.
4358
+
4359
+ If tasks were only able to capture these values, they wouldn't be very useful.
4360
+ Luckily, tasks can communicate with each other through ** channel** s. Channels
4361
+ work like this:
4362
+
4363
+ ``` {rust}
4364
+ let (tx, rx) = channel();
4365
+
4366
+ spawn(proc() {
4367
+ tx.send("Hello from a task!".to_string());
4368
+ });
4369
+
4370
+ let message = rx.recv();
4371
+ println!("{}", message);
4372
+ ```
4373
+
4374
+ The ` channel() ` function returns two endpoints: a ` Receiver<T> ` and a
4375
+ ` Sender<T> ` . You can use the ` .send() ` method on the ` Sender<T> ` end, and
4376
+ receive the message on the ` Receiver<T> ` side with the ` recv() ` method. This
4377
+ method blocks until it gets a message. There's a similar method, ` .try_recv() ` ,
4378
+ which returns an ` Option<T> ` and does not block.
4379
+
4380
+ If you want to send messages to the task as well, create two channels!
4381
+
4382
+ ``` {rust}
4383
+ let (tx1, rx1) = channel();
4384
+ let (tx2, rx2) = channel();
4385
+
4386
+ spawn(proc() {
4387
+ tx1.send("Hello from a task!".to_string());
4388
+ let message = rx2.recv();
4389
+ println!("{}", message);
4390
+ });
4391
+
4392
+ let message = rx1.recv();
4393
+ println!("{}", message);
4394
+
4395
+ tx2.send("Goodbye from main!".to_string());
4396
+ ```
4397
+
4398
+ The proc has one sending end and one receiving end, and the main task has one
4399
+ of each as well. Now they can talk back and forth in whatever way they wish.
4400
+
4401
+ Notice as well that because ` Sender ` and ` Receiver ` are generic, while you can
4402
+ pass any kind of information through the channel, the ends are strongly typed.
4403
+ If you try to pass a string, and then an integer, Rust will complain.
4404
+
4405
+ ## Futures
4406
+
4407
+ With these basic primitives, many different concurrency patterns can be
4408
+ developed. Rust includes some of these types in its standard library. For
4409
+ example, if you wish to compute some value in the background, ` Future ` is
4410
+ a useful thing to use:
4411
+
4412
+ ``` {rust}
4413
+ use std::sync::Future;
4414
+
4415
+ let mut delayed_value = Future::spawn(proc() {
4416
+ // just return anything for examples' sake
4417
+
4418
+ 12345i
4419
+ });
4420
+ println!("value = {}", delayed_value.get());
4421
+ ```
4422
+
4423
+ Calling ` Future::spawn ` works just like ` spawn() ` : it takes a proc. In this
4424
+ case, though, you don't need to mess with the channel: just have the proc
4425
+ return the value.
4426
+
4427
+ ` Future::spawn ` will return a value which we can bind with ` let ` . It needs
4428
+ to be mutable, because once the value is computed, it saves a copy of the
4429
+ value, and if it were immutable, it couldn't update itself.
4430
+
4431
+ The proc will go on processing in the background, and when we need the final
4432
+ value, we can call ` get() ` on it. This will block until the result is done,
4433
+ but if it's finished computing in the background, we'll just get the value
4434
+ immediately.
4435
+
4436
+ ## Success and failure
4437
+
4438
+ Tasks don't always succeed, they can also fail. A task that wishes to fail
4439
+ can call the ` fail! ` macro, passing a message:
4440
+
4441
+ ``` {rust}
4442
+ spawn(proc() {
4443
+ fail!("Nope.");
4444
+ });
4445
+ ```
4446
+
4447
+ If a task fails, it is not possible for it to recover. However, it can
4448
+ notify other tasks that it has failed. We can do this with ` task::try ` :
4449
+
4450
+ ``` {rust}
4451
+ use std::task;
4452
+ use std::rand;
4453
+
4454
+ let result = task::try(proc() {
4455
+ if rand::random() {
4456
+ println!("OK");
4457
+ } else {
4458
+ fail!("oops!");
4459
+ }
4460
+ });
4461
+ ```
4462
+
4463
+ This task will randomly fail or succeed. ` task::try ` returns a ` Result `
4464
+ type, so we can handle the response like any other computation that may
4465
+ fail.
4466
+
4321
4467
# Macros
4322
4468
4323
4469
# Unsafe
0 commit comments