Skip to content

Commit

Permalink
Merge pull request #11 from kassane/multihread-ptbr
Browse files Browse the repository at this point in the history
D Multithreads on pt_BR
  • Loading branch information
sergiors authored Feb 16, 2024
2 parents d69f3a4 + fb8fc85 commit 6b561ea
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 207 deletions.
80 changes: 39 additions & 41 deletions multithreading/fibers.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
# Fibers
# Fibras

**Fibers** are a way to implemented concurrency
in a *cooperative* fashion. The class `Fiber`
is defined in the module [`core.thread`](https://dlang.org/phobos/core_thread.html).
**Fibras** são uma forma de implementar a concorrência
de forma *cooperativa*. A classe `Fiber`
é definida no módulo [`core.thread`](https://dlang.org/phobos/core_thread.html).

The basic idea is that when a fiber
has nothing to do or waits for more input, it
*actively* gives away its possibility to
execute instructions by calling `Fiber.yield()`.
The parent context gains now power again but the
fiber's state - all variables on the stack - are
saved. The fiber can then be resumed
and will continue at the instruction right *after*
it called `Fiber.yield()`. Magic? Yes.
A ideia básica é que, quando uma fibra
não tem nada para fazer ou espera por mais entrada, ela
*ativamente* abre mão de sua possibilidade de
executar instruções chamando `Fiber.yield()`.
O contexto principal ganha controle novamente,
mas o estado da fibra - todas as variáveis na pilha - são
salvas. A fibra pode então ser retomada
e continuará na instrução logo *depois* de chamar `Fiber.yield()`.

void foo() {
writeln("Hello");
Expand All @@ -21,38 +20,37 @@ it called `Fiber.yield()`. Magic? Yes.
}
// ...
auto f = new Fiber(&foo);
f.call(); // Prints Hello
f.call(); // Prints World
f.call(); // Imprime Hello
f.call(); // Imprime World

This feature can be used to implement concurrency
where multiple fibers cooperatively share a single
core. The advantage of fibers compared to threads is
that there resource usage is lower because
no context switching is involved.
Esse recurso pode ser usado para implementar a concorrência
em que várias fibras compartilham cooperativamente um único
núcleo. A vantagem das fibras em relação as threads
é que seu uso de recursos é menor porque
não há troca de contexto envolvida.

A very good usage of this technique can be seen in
the [vibe.d framework](http://vibed.org) which implements
non-blocking (or asynchronous) I/O operations
in terms of fibers leading to a much cleaner
code.
Um uso muito bom dessa técnica pode ser visto em
[vibe.d](http://vibed.org), que implementa
operações de E/S não bloqueantes (ou assíncronas)
em termos de fibras, o que resulta em um código muito mais limpo.

### In-depth
### Maiores detalhes

- [Fibers in _Programming in D_](http://ddili.org/ders/d.en/fibers.html)
- [Documentation of core.thread.Fiber](https://dlang.org/library/core/thread/fiber.html)

## {SourceCode}

```d
import core.thread: Fiber;
import std.stdio: write;
import std.range: iota;
import core.thread : Fiber;
import std.stdio : write;
import std.range : iota;
/**
Iterates over `range` and applies
the function `Fnc` to each element x
and returns it in `result`. Fiber yields
after each application.
Itera sobre o `range` e aplica
a função `Fnc` a cada elemento x
e o retorna em `result`. A fibra libera
após cada aplicação.
*/
void fiberedRange(alias Fnc, R, T)(
R range,
Expand All @@ -67,21 +65,21 @@ void fiberedRange(alias Fnc, R, T)(
void main()
{
int squareResult, cubeResult;
// Create a fiber that is initialized
// with a delegate that generates a square
// range.
// Cria uma fibra que é inicializada
// com um delegate que gera uma raíz
// quadrada com range.
auto squareFiber = new Fiber({
fiberedRange!(x => x*x)(
iota(1,11), squareResult);
});
// .. and here is which creates cubes!
// .. e aqui criará raíz cúbica!
auto cubeFiber = new Fiber({
fiberedRange!(x => x*x*x)(
iota(1,9), cubeResult);
});
// if state is TERM the fiber has finished
// executing its associated function.
// Se o estado for TERM, a fibra finaliza
// executando sua função associada.
squareFiber.call();
cubeFiber.call();
while (squareFiber.state
Expand All @@ -94,7 +92,7 @@ void main()
write("\n");
}
// squareFiber could still be run because
// it has finished yet!
// squareFiber ainda pode ser executado
// porque ele ainda não terminou!
}
```
2 changes: 1 addition & 1 deletion multithreading/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ ordering:
- message-passing
- synchronization-sharing
- std-parallelism
- fibers
- fibers
53 changes: 26 additions & 27 deletions multithreading/message-passing.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# Message Passing

Instead of dealing with threads and doing synchronization
yourself D allows to use *message passing* as a means
to leverage the power of multiple cores. Threads communicate
with *messages* - which are arbitrary values - to distribute
work and synchronize themselves. They don't share data
by design which avoids the common problems of
# Troca de Mensagens

Em vez de lidar com threads e fazer a sincronização
você mesmo, o D permite usar a *troca de mensagens* como um meio
para aproveitar a potência de vários núcleos. As threads se comunicam
com *mensagens*, que são valores arbitrários, para distribuir
trabalho e sincronizar-se. Eles não compartilham dados
por padrão, o que evita os problemas comuns de
multi-threading.

All functions that implement message passing in D
can be found in the [`std.concurrency`](https://dlang.org/phobos/std_concurrency.html)
module. `spawn` creates a new *thread* based on a
user-defined function:
Todas as funções que implementam a troca de mensagens em D
podem ser encontradas no módulo [`std.concurrency`](https://dlang.org/phobos/std_concurrency.html)
módulo. O `spawn` cria uma nova *thread* com base em uma
função definida pelo usuário:

auto threadId = spawn(&foo, thisTid);

`thisTid` is a `std.concurrency` built-in and references
the current thread which is needed for message passing. `spawn`
takes a function as first parameter and
additional parameters to that function as arguments.
`thisTid` faz parte do `std.concurrency` e faz referência a
thread atual, que é necessário para a troca de mensagens. `spawn`
recebe uma função como primeiro parâmetro e
parâmetros adicionais para essa função como argumentos.

void foo(Tid parentTid) {
receive(
Expand All @@ -28,27 +28,26 @@ additional parameters to that function as arguments.
send(parentTid, "Done");
}

The `receive` function is like a `switch`-`case`
and dispatches the values it receives from other threads
to the passed `delegates` - depending on the received
value's type.
A função `receive` é como um `switch`-`case`
e despacha os valores que recebe de outras threads
para os `delegates` enviados, dependendo do tipo de valor recebido.

To send a message to a specific thread use the function `send`
and its id:
Para enviar uma mensagem a uma thread específico, use a função `send`
e seu identificador:

send(threadId, 42);

`receiveOnly` can be used to just receive a specified
type:
O `receiveOnly` pode ser usado para receber apenas um
tipo especificado:

string text = receiveOnly!string();
assert(text == "Done");

The `receive` family functions block until something
has been sent to the thread's mailbox.
As funções da família `receive` bloqueiam até que algo
tenha sido enviado para a caixa de correio da thread.


### In-depth
### Maiores detalhes

- [Exchanging Messages between Threads](http://www.informit.com/articles/article.aspx?p=1609144&seqNum=5)
- [Messaging passing concurrency](http://ddili.org/ders/d.en/concurrency.html)
Expand Down
104 changes: 53 additions & 51 deletions multithreading/std-parallelism.md
Original file line number Diff line number Diff line change
@@ -1,104 +1,105 @@
# std.parallelism

The module `std.parallelism` implements
high level primitives for convenient concurrent programming.
O módulo `std.parallelism` implementa
primitivas de alto nível para uma programação simultânea conveniente.

### parallel
### Parallel

[`std.parallelism.parallel`](http://dlang.org/phobos/std_parallelism.html#.parallel) allows to automatically distribute
a `foreach`'s body to different threads:
[`std.parallelism.parallel`](http://dlang.org/phobos/std_parallelism.html#.parallel) permite distribuir automaticamente
o corpo de um `foreach` para diferentes threads:

// parallel squaring of arr
// raíz quadrada em paralelo
// dos elementos arr
auto arr = iota(1,100).array;
foreach(ref i; parallel(arr)) {
i = i*i;
}

`parallel` uses the `opApply` operator internally.
The global `parallel` is a shortcut to `taskPool.parallel`
which is a `TaskPool` that uses *total number of cpus - 1*
working threads. Creating your own instance allows
to control the degree of parallelism.
`parallel` utiliza internamente o operador `opApply`.
`parallel` global é um atalho para o `taskPool.parallel`
que é um `TaskPool` que usa *número total de cpus - 1*
de _working threads_. Criar sua própria instância permite
controlar o grau de paralelismo.

Beware that the body of a `parallel` iteration must
make sure that it doesn't modify items that another
working unit might have access to.
Observe que o corpo de uma iteração `parallel` deve
garantir que não modifique itens aos quais outra
unidade de trabalho possa ter acesso.

The optional `workingUnitSize` specifies the number of elements processed
per worker thread.
O `workingUnitSize` opcional especifica o número de elementos processados
por __worker thread__.

### reduce

The function
A função
[`std.algorithm.iteration.reduce`](http://dlang.org/phobos/std_algorithm_iteration.html#reduce) -
known from other functional contexts as *accumulate* or *foldl* -
calls a function `fun(acc, x)` for each element `x`
where `acc` is the previous result:
conhecida em outros contextos funcionais como *accumulate* ou *foldl* -
chama uma função `fun(acc, x)` para cada elemento `x`
em que `acc` é o resultado anterior:

// 0 is the "seed"
// 0 é a "semente"
auto sum = reduce!"a + b"(0, elements);

[`Taskpool.reduce`](http://dlang.org/phobos/std_parallelism.html#.TaskPool.reduce)
is the parallel analog to `reduce`:
é o análogo paralelo do `reduce`:

// Find the sum of a range in parallel, using the first
// element of each work unit as the seed.
// Encontre a soma de um range em paralelo, usando o primeiro
// elemento de cada unidade de trabalho como semente.
auto sum = taskPool.reduce!"a + b"(nums);

`TaskPool.reduce` splits the range into
sub ranges that are reduced in parallel. Once these
results have been calculated, the results are reduced
themselves.
O `TaskPool.reduce` divide o range em
sub-ranges que são reduzidos em paralelo. Depois que esses
resultados tiverem sido calculados, os resultados serão reduzidos
por si mesmos.

### `task()`

[`task`](http://dlang.org/phobos/std_parallelism.html#.task) is a wrapper for a function
that might take longer or should be executed in
its own working thread. It can either be enqueued
in a taskpool:
[`task`](http://dlang.org/phobos/std_parallelism.html#.task) é um wrapper para uma função
que pode demorar mais ou que deve ser executada em
sua própria __worker thread__. Ela pode ser enfileirada
em um *taskpool*:

auto t = task!read("foo.txt");
taskPool.put(t);

Or directly be executed in its own, new thread:
Ou ser executado diretamente em sua própria e nova thread:

t.executeInNewThread();

To get a task's result call `yieldForce`
on it. It will block until the result is available.
Para obter o resultado de uma __task__, chame `yieldForce`
sobre ela. Ela será bloqueada até que o resultado esteja disponível.

auto fileData = t.yieldForce;

### In-depth
### Maiores detalhes

- [Parallelism in _Programming in D_](http://ddili.org/ders/d.en/parallelism.html)
- [std.parallelism](http://dlang.org/phobos/std_parallelism.html)

## {SourceCode}

```d
import std.parallelism;
import std.array: array;
import std.stdio: writeln;
import std.range: iota;
import std.parallelism : task,
taskPool, TaskPool;
import std.array : array;
import std.stdio : writeln;
import std.range : iota;
string theTask()
{
import core.thread;
import core.thread : dur, Thread;
Thread.sleep( dur!("seconds")(1) );
return "Hello World";
}
void main()
{
// taskpool with two threads
// taskpool com duas threads
auto myTaskPool = new TaskPool(2);
// Stopping the task pool is important!
// Interromper taskpool é importante!
scope(exit) myTaskPool.stop();
// Start long running task
// and do some other stuff in the mean
// time..
// Começa executnado uma task
// que durará um certo tempo
auto task = task!theTask;
myTaskPool.put(task);
Expand All @@ -109,16 +110,17 @@ void main()
writeln(arr);
import std.algorithm: map;
import std.algorithm.iteration : map;
// Use reduce to calculate the sum
// of all squares in parallel.
// Usa reduce para calcular a soma
// de todas as raizes quadradas
// paralelamente.
auto result = taskPool.reduce!"a+b"(
0.0, iota(100).map!"a*a");
writeln("Sum of squares: ", result);
// Get our result we sent to background
// earlier.
// Pega o resultado em segundo-plano
// antecipadamente.
writeln(task.yieldForce);
}
```
Loading

0 comments on commit 6b561ea

Please sign in to comment.