Параллельность — это выполнение программы одновременно несколькими потоками. Примером параллельной программы является веб-сервер, отвечающий одновременно нескольким клиентам. Параллелизм прост с передачей сообщений, но очень трудно писать, если они основаны на обмене данными.
Данные, которые передаются между потоками, называются сообщениями. Сообщения могут состоять из любого типа и любого количества переменных. Каждый поток имеет идентификатор, который используется для указания получателей сообщений. Любой поток, который запускает другой поток, называется владельцем нового потока.
Инициирование потоков в D
Функция spawn () принимает указатель в качестве параметра и запускает новый поток из этой функции. Любые операции, выполняемые этой функцией, включая другие функции, которые она может вызывать, будут выполняться в новом потоке. Владелец и рабочий оба начинают выполняться отдельно, как если бы они были независимыми программами.
пример
import std.stdio; import std.stdio; import std.concurrency; import core.thread; void worker(int a) { foreach (i; 0 .. 4) { Thread.sleep(1); writeln("Worker Thread ",a + i); } } void main() { foreach (i; 1 .. 4) { Thread.sleep(2); writeln("Main Thread ",i); spawn(≈worker, i * 5); } writeln("main is done."); }
Когда приведенный выше код компилируется и выполняется, он читает файл, созданный в предыдущем разделе, и выдает следующий результат:
Main Thread 1 Worker Thread 5 Main Thread 2 Worker Thread 6 Worker Thread 10 Main Thread 3 main is done. Worker Thread 7 Worker Thread 11 Worker Thread 15 Worker Thread 8 Worker Thread 12 Worker Thread 16 Worker Thread 13 Worker Thread 17 Worker Thread 18
Идентификаторы потока в D
Переменная thisTid, доступная глобально на уровне модуля, всегда является идентификатором текущего потока. Также вы можете получить threadId при вызове spawn. Пример показан ниже.
пример
import std.stdio; import std.concurrency; void printTid(string tag) { writefln("%s: %s, address: %s", tag, thisTid, &thisTid); } void worker() { printTid("Worker"); } void main() { Tid myWorker = spawn(&worker); printTid("Owner "); writeln(myWorker); }
Когда приведенный выше код компилируется и выполняется, он читает файл, созданный в предыдущем разделе, и выдает следующий результат:
Owner : Tid(std.concurrency.MessageBox), address: 10C71A59C Worker: Tid(std.concurrency.MessageBox), address: 10C71A59C Tid(std.concurrency.MessageBox)
Передача сообщений в D
Функция send () отправляет сообщения, а функция receiveOnly () ожидает сообщения определенного типа. Есть другие функции с именем prioritySend (), receive () и receiveTimeout (), которые будут объяснены позже.
Владелец в следующей программе отправляет своему работнику сообщение типа int и ожидает сообщения от работника типа double. Потоки продолжают отправлять сообщения туда и обратно, пока владелец не отправит отрицательный int. Пример показан ниже.
пример
import std.stdio; import std.concurrency; import core.thread; import std.conv; void workerFunc(Tid tid) { int value = 0; while (value >= 0) { value = receiveOnly!int(); auto result = to!double(value) * 5; tid.send(result); } } void main() { Tid worker = spawn(&workerFunc,thisTid); foreach (value; 5 .. 10) { worker.send(value); auto result = receiveOnly!double(); writefln("sent: %s, received: %s", value, result); } worker.send(-1); }
Когда приведенный выше код компилируется и выполняется, он читает файл, созданный в предыдущем разделе, и выдает следующий результат:
sent: 5, received: 25 sent: 6, received: 30 sent: 7, received: 35 sent: 8, received: 40 sent: 9, received: 45
Передача сообщения с ожиданием в D
Простой пример передачи сообщения с ожиданием показан ниже.
import std.stdio; import std.concurrency; import core.thread; import std.conv; void workerFunc(Tid tid) { Thread.sleep(dur!("msecs")( 500 ),); tid.send("hello"); } void main() { spawn(&workerFunc,thisTid); writeln("Waiting for a message"); bool received = false; while (!received) { received = receiveTimeout(dur!("msecs")( 100 ), (string message) { writeln("received: ", message); }); if (!received) { writeln("... no message yet"); } } }
Когда приведенный выше код компилируется и выполняется, он читает файл, созданный в предыдущем разделе, и выдает следующий результат: