D 程式設計 - 併發



併發是指程式在同一時間內執行多個執行緒。一個併發程式的例子是 Web 伺服器同時響應多個客戶端。併發使用訊息傳遞很容易實現,但如果基於資料共享則非常難以編寫。

線上程之間傳遞的資料稱為訊息。訊息可以由任何型別和任意數量的變數組成。每個執行緒都有一個 ID,用於指定訊息的接收者。任何啟動另一個執行緒的執行緒都稱為新執行緒的所有者。

在 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 變數始終是當前執行緒的 ID。您也可以在呼叫 spawn 時接收執行緒 ID。下面顯示了一個示例。

示例

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"); 
      }
   } 
}

當以上程式碼編譯並執行時,它讀取上一節中建立的檔案併產生以下結果:

Waiting for a message 
... no message yet 
... no message yet 
... no message yet 
... no message yet 
received: hello 
廣告