由於Dart
是一種單執行緒模型語言,所以避免了多執行緒環境下產生的一系列降低執行效率的問題。但單執行緒模型卻有一個非常嚴重的問題,就是耗時任務的執行。當執行耗時任務時,會導致當前執行緒會被阻塞,從而無法繼續執行。這時候就需要非同步任務,而Dart
提供了Isolate
來執行非同步任務。
在剛開始學習Isolate
時,以為它類似Java
、C/CPP
中的執行緒。但隨著學習的深入,發現Isolate
遠比Java
、C/CPP
中的執行緒複雜。下面就來一窺究竟。
1、Isolate的使用
在Dart
中,Isolate
的使用及通訊都較為複雜,主要是通過
Isolate.spawn
及Isolate.spawnUri
來建立Isolate
,ReceivePort
來進行Isolate
間通訊。下面就來看如何使用Isolate
。
1.1、Isolate單向通訊
先來看Isolate
間的單向通訊,程式碼如下。
//在父Isolate中呼叫
Isolate isolate;
start() async {
ReceivePort receivePort = ReceivePort();
//建立子Isolate物件
isolate = await Isolate.spawn(getMsg, receivePort.sendPort);
//監聽子Isolate的返回資料
receivePort.listen((data) {
print('data:$data');
receivePort.close();
//關閉Isolate物件
isolate?.kill(priority: Isolate.immediate);
isolate = null;
});
}
//子Isolate物件的入口函式,可以在該函式中做耗時操作
getMsg(sendPort) => sendPort.send("hello");
複製程式碼
執行程式碼後,就會輸出新建立Isolate
物件返回的資料,如下。
1.2、Isolate雙向通訊
再來看多個Isolate
之間的通訊實現,程式碼如下。
//當前函式在父Isolate中
Future<dynamic> asyncFactoriali(n) async {
//父Isolate對應的ReceivePort物件
final response = ReceivePort();
//建立一個子Isolate物件
await Isolate.spawn(_isolate, response.sendPort);
final sendPort = await response.first as SendPort;
final answer = ReceivePort();
//給子Isolate傳送資料
sendPort.send([n, answer.sendPort]);
return answer.first;
}
//子Isolate的入口函式,可以在該函式中做耗時操作
_isolate(SendPort initialReplyTo) async {
//子Isolate對應的ReceivePort物件
final port = ReceivePort();
initialReplyTo.send(port.sendPort);
final message = await port.first as List;
final data = message[0] as int;
final send = message[1] as SendPort;
//給父Isolate的返回資料
send.send(syncFactorial(data));
}
//執行程式碼
start() async {
print("計算結果:${await asyncFactoriali(4)}");
}
start();
複製程式碼
通過在新建立的Isolate
中計算並返回資料後,得到如下返回結果。
通過上面程式碼,我們就可以能夠通過Isolate
來執行非同步任務。下面再來看其具體實現原理。
2、isolate的建立與執行
先從下面的時序圖來看isolate
是如何建立及執行的。
isolate
的建立及執行兩方面來對上圖進行詳細介紹。
2.1、isolate的建立
首先來看isolate
的建立,在上面例子中是通過Isolate.spawn
來建立Isolate
物件。
class Isolate {
//宣告外部實現
external static Future<Isolate> spawn<T>(
void entryPoint(T message), T message,
{bool paused: false,
bool errorsAreFatal,
SendPort onExit,
SendPort onError,
@Since("2.3") String debugName});
}
複製程式碼
這裡的external
關鍵字主要是宣告spawn
這個函式,具體實現由外部提供。在Dart
中,該函式的具體實現是在isolate_patch.dart
中。先來看spawn
的具體實現。
@patch
class Isolate {
@patch
static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
{bool paused: false,
bool errorsAreFatal,
SendPort onExit,
SendPort onError,
String debugName}) async {
// `paused` isn't handled yet.
RawReceivePort readyPort;
try {
//該函式執行是非同步的
_spawnFunction(
readyPort.sendPort,
script.toString(),
entryPoint,
message,
paused,
errorsAreFatal,
onExit,
onError,
null,
packageConfig,
debugName);
return await _spawnCommon(readyPort);
} catch (e, st) {
...
}
}
static Future<Isolate> _spawnCommon(RawReceivePort readyPort) {
Completer completer = new Completer<Isolate>.sync();
//監聽Isolate是否建立完畢,當子Isolate建立完畢後會通知父Isolate
readyPort.handler = (readyMessage) {
//關閉埠
readyPort.close();
if (readyMessage is List && readyMessage.length == 2) {//子Isolate建立成功
SendPort controlPort = readyMessage[0];
List capabilities = readyMessage[1];
completer.complete(new Isolate(controlPort,
pauseCapability: capabilities[0],
terminateCapability: capabilities[1]));
} else if (readyMessage is String) {...} else {...}
};
return completer.future;
}
......
//呼叫虛擬機器中的Isolate_spawnFunction函式
static void _spawnFunction(
SendPort readyPort,
String uri,
Function topLevelFunction,
var message,
bool paused,
bool errorsAreFatal,
SendPort onExit,
SendPort onError,
String packageRoot,
String packageConfig,
String debugName) native "Isolate_spawnFunction";
......
}
複製程式碼
這裡的_spawnFunction
呼叫的是Dart VM中的Isolate_spawnFunction
函式,該函式就是把Isolate
物件的建立交給執行緒池執行,所以Isolate
物件的建立是非同步的。這裡的執行緒池是在Dart VM初始化的時候建立的。
[->third_party/dart/runtime/lib/isolate.cc]
DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 0, 11) {
...
if (closure.IsClosure()) {
...
//非同步執行,thread_pool是一個執行緒池
Dart::thread_pool()->Run<SpawnIsolateTask>(isolate, std::move(state));
return Object::null();
}
}
...
return Object::null();
}
複製程式碼
SpawnIsolateTask
是一個類似Java中實現了Runable
介面的類,在該類中主要是進行子Isolate
物件的建立及執行,來看其具體實現。
[->third_party/dart/runtime/lib/isolate.cc]
//在子執行緒中執行
class SpawnIsolateTask : public ThreadPool::Task {
void Run() override {
...
// initialize_callback對應[->third_party/dart/runtime/bin/main.cc]中的OnIsolateInitialize函式
// OnIsolateInitialize是在Dart VM初始化時設定的
//[見小節2.2]
Dart_InitializeIsolateCallback initialize_callback =
Isolate::InitializeCallback();
...
// Create a new isolate.
char* error = nullptr;
Isolate* isolate = nullptr;
//在AOT編譯環境下,FLAG_enable_isolate_groups為true,否則為false
//group及initialize_callback都是在虛擬機器初始化的時候設定的
if (!FLAG_enable_isolate_groups || group == nullptr ||
initialize_callback == nullptr) {
...
} else {
...
//先直接看AOT編譯下的Isolate建立
isolate = CreateWithinExistingIsolateGroup(group, name, &error);
...
void* child_isolate_data = nullptr;
//將Isolate設定為可執行
//[見2.2小節]
bool success = initialize_callback(&child_isolate_data, &error);
}
//建立失敗
if (isolate == nullptr) {
FailedSpawn(error);
free(error);
return;
}
...
// isolate是否是可執行的
// 是在OnIsolateInitialize中設定的
if (isolate->is_runnable()) {
//執行isolate
//[見2.2小節]
isolate->Run();
}
}
};
複製程式碼
AOT編譯下,在子執行緒中呼叫CreateWithinExistingIsolateGroup
函式來建立Isolate
物件。
[->third_party/dart/runtime/vm/dart_api_impl.cc]
Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* group,
const char* name,
char** error) {
//建立Isolate物件
Isolate* isolate = reinterpret_cast<Isolate*>(
CreateIsolate(group, name, /*isolate_data=*/nullptr, error));
...
return isolate;
}
...
static Dart_Isolate CreateIsolate(IsolateGroup* group,
const char* name,
void* isolate_data,
char** error) {
auto source = group->source();
Isolate* I = Dart::CreateIsolate(name, source->flags, group);
...
Dart::ShutdownIsolate();
return reinterpret_cast<Dart_Isolate>(NULL);
}
複製程式碼
經過一系列呼叫,最終呼叫dart.cc中的CreateIsolate
函式,該函式很簡單,就是建立一個新的Isolate
物件。
[->third_party/dart/runtime/vm/dart.cc]
Isolate* Dart::CreateIsolate(const char* name_prefix,
const Dart_IsolateFlags& api_flags,
IsolateGroup* isolate_group) {
// Create a new isolate.
Isolate* isolate =
Isolate::InitIsolate(name_prefix, isolate_group, api_flags);
return isolate;
}
複製程式碼
[->third_party/dart/runtime/vm/isolate.cc]
//初始化Isolate
Isolate* Isolate::InitIsolate(const char* name_prefix,
IsolateGroup* isolate_group,
const Dart_IsolateFlags& api_flags,
bool is_vm_isolate) {
//1、建立一個Isolate物件
Isolate* result = new Isolate(isolate_group, api_flags);
...
//2、建立Isolate對應的堆空間,在該堆空間中,存在物件的分配,垃圾回收等。
Heap::Init(result,
is_vm_isolate
? 0 // New gen size 0; VM isolate should only allocate in old.
: FLAG_new_gen_semi_max_size * MBInWords,//MBInWords值是128kb,
(is_service_or_kernel_isolate ? kDefaultMaxOldGenHeapSize
: FLAG_old_gen_heap_size) *
MBInWords);
//3、將Isolate與Thread相關聯
if (!Thread::EnterIsolate(result)) {
// We failed to enter the isolate, it is possible the VM is shutting down,
// return back a NULL so that CreateIsolate reports back an error.
if (KernelIsolate::IsKernelIsolate(result)) {
KernelIsolate::SetKernelIsolate(nullptr);
}
if (ServiceIsolate::IsServiceIsolate(result)) {
ServiceIsolate::SetServiceIsolate(nullptr);
}
delete result;
return nullptr;
}
// Setup the isolate message handler.
//4、設定isolate的訊息處理器
MessageHandler* handler = new IsolateMessageHandler(result);
result->set_message_handler(handler);
// Setup the Dart API state.
//5、啟動Dart API狀態
ApiState* state = new ApiState();
result->set_api_state(state);
//6、設定主埠
result->set_main_port(PortMap::CreatePort(result->message_handler()));
// Add to isolate list. Shutdown and delete the isolate on failure.
//7、將當前的Isolate新增到連結串列中(一個單連結串列)
if (!AddIsolateToList(result)) {
//新增失敗,銷燬該Isolate
result->LowLevelShutdown();
//取消執行緒與Isolate的關聯
Thread::ExitIsolate();
//如果是虛擬機器內部的Isolate
if (KernelIsolate::IsKernelIsolate(result)) {
KernelIsolate::SetKernelIsolate(nullptr);
}
//如果是Service Isolate
if (ServiceIsolate::IsServiceIsolate(result)) {
ServiceIsolate::SetServiceIsolate(nullptr);
}
//刪除當前Isolate物件
delete result;
return nullptr;
}
return result;
}
複製程式碼
InitIsolate
函式比較重要,主要做了以下事情。
- 建立
Isolate
物件 - 建立
Isolate
中的堆空間,在Isolate
僅有一塊堆空間。存在堆空間也就會存在物件分配、垃圾回收等。 - 將
Isolate
物件與一個執行緒進行關聯,也就是可以說一個執行緒對應著一個Isolate
物件。 - 設定訊息處理器(
IsolateMessageHandler
),主要是對於Isolate
中的訊息處理。子Isolate
可以通過埠向父Isolate
的MessageHandler
中新增訊息,反之亦然。這也是Isolate
間的通訊的實現。 - 設定api state,暫時沒搞懂這個是幹啥的。
- 設定主埠。
- 將當前
Isolate
新增到連結串列中。
當上面的一些操作執行完畢後,一個Isolate
物件就建立成功了。
2.2、isolate的執行
再回到SpawnIsolateTask
類中,當呼叫CreateWithinExistingIsolateGroup
建立Isolate
成功後,也僅是建立了一個Isolate
物件。這時候的Isolate
並未執行,也不能執行該Isolate
中的任何程式碼。所以還得主動呼叫Isolate
的Run
函式,使Isolate
能夠執行其中的程式碼並執行相應的訊息。
首先需要通過initialize_callback
函式來將Isolate
設定為可執行。initialize_callback
函式在Dart VM初始化的時候設定,對應著[->third_party/dart/runtime/bin/main.cc]中的OnIsolateInitialize
函式。把Isolate
設定為可執行後,才可以執行Isolate
。
[->third_party/dart/runtime/vm/isolate.cc]
void Isolate::Run() {
//向訊息處理器中新增的第一個訊息
//記住該RunIsolate函式,在後面會說到
message_handler()->Run(Dart::thread_pool(), RunIsolate, ShutdownIsolate,
reinterpret_cast<uword>(this));
}
複製程式碼
[->third_party/dart/runtime/vm/MessageHandler.cc]
void MessageHandler::Run(ThreadPool* pool,
StartCallback start_callback,
EndCallback end_callback,
CallbackData data) {
MonitorLocker ml(&monitor_);
pool_ = pool;
start_callback_ = start_callback;
end_callback_ = end_callback;
callback_data_ = data;
task_running_ = true;
//線上程池中執行任務
const bool launched_successfully = pool_->Run<MessageHandlerTask>(this);
}
複製程式碼
然後繼續非同步執行,但這次是在子Isolate
中執行的。下面再來看MessageHandlerTask
,在MessageHandlerTask
的run
函式中執行的是TaskCallback
函式。
[->third_party/dart/runtime/vm/message_handler.cc]
void MessageHandler::TaskCallback() {
MessageStatus status = kOK;
bool run_end_callback = false;
bool delete_me = false;
EndCallback end_callback = NULL;
CallbackData callback_data = 0;
{
...
if (status == kOK) {
//僅當子Isolate第一次執行時,start_callback_才不為null
if (start_callback_ != nullptr) {
ml.Exit();
//呼叫Isolate的第一個函式(允許多執行緒併發執行)
status = start_callback_(callback_data_);
ASSERT(Isolate::Current() == NULL);
start_callback_ = NULL;
ml.Enter();
}
...
}
...
}
...
}
複製程式碼
先不管訊息處理[見小結3],這裡重點來看start_callback_
,它對應著RunIsolate
這個函式。
[->third_party/dart/runtime/vm/isolate.cc]
//執行Isolate
static MessageHandler::MessageStatus RunIsolate(uword parameter) {
...
{
...
//args是呼叫Dart層_startIsolate函式所需的引數集合
const Array& args = Array::Handle(Array::New(7));
args.SetAt(0, SendPort::Handle(SendPort::New(state->parent_port())));
args.SetAt(1, Instance::Handle(func.ImplicitStaticClosure()));
args.SetAt(2, Instance::Handle(state->BuildArgs(thread)));
args.SetAt(3, Instance::Handle(state->BuildMessage(thread)));
args.SetAt(4, is_spawn_uri ? Bool::True() : Bool::False());
args.SetAt(5, ReceivePort::Handle(ReceivePort::New(
isolate->main_port(), true /* control port */)));
args.SetAt(6, capabilities);
//呼叫Dart層的_startIsolate函式,該函式在isolate_patch.dart檔案中
const Library& lib = Library::Handle(Library::IsolateLibrary());
const String& entry_name = String::Handle(String::New("_startIsolate"));
const Function& entry_point =
Function::Handle(lib.LookupLocalFunction(entry_name));
ASSERT(entry_point.IsFunction() && !entry_point.IsNull());
result = DartEntry::InvokeFunction(entry_point, args);
if (result.IsError()) {
return StoreError(thread, Error::Cast(result));
}
}
return MessageHandler::kOK;
}
複製程式碼
在RunIsolate
中,會呼叫isolate_patch.dart
中的_startIsolate
函式,從而呼叫建立Isolate
物件時傳遞的初始化函式。
@pragma("vm:entry-point", "call")
void _startIsolate(
SendPort parentPort,
Function entryPoint,
List<String> args,
var message,
bool isSpawnUri,
RawReceivePort controlPort,
List capabilities) {
// The control port (aka the main isolate port) does not handle any messages.
if (controlPort != null) {
controlPort.handler = (_) {}; // Nobody home on the control port.
}
if (parentPort != null) {
// Build a message to our parent isolate providing access to the
// current isolate's control port and capabilities.
//
// TODO(floitsch): Send an error message if we can't find the entry point.
var readyMessage = new List(2);
readyMessage[0] = controlPort.sendPort;
readyMessage[1] = capabilities;
// Out of an excess of paranoia we clear the capabilities from the
// stack. Not really necessary.
capabilities = null;
//告訴父Isolate,當前`Isolate`已經建立成功
parentPort.send(readyMessage);
}
// Delay all user code handling to the next run of the message loop. This
// allows us to intercept certain conditions in the event dispatch, such as
// starting in paused state.
RawReceivePort port = new RawReceivePort();
port.handler = (_) {
port.close();
if (isSpawnUri) {
if (entryPoint is _BinaryFunction) {
(entryPoint as dynamic)(args, message);
} else if (entryPoint is _UnaryFunction) {
(entryPoint as dynamic)(args);
} else {
entryPoint();
}
} else {
//初始化函式
entryPoint(message);
}
};
// Make sure the message handler is triggered.
port.sendPort.send(null);
}
複製程式碼
在_startIsolate
函式中主要是做了以下幾件事。
- 告訴父
Isolate
,子Isolate
已經建立成功。 - 呼叫子
Isolate
的初始化函式,也就是入口函式。
到此,一個新的Isolate
就已經建立完畢。在建立過程中,會從Dart SDK呼叫虛擬機器函式,然後在新的Isolate
物件中通過非同步的方式呼叫入口函式。
注意:主Isolate
的入口函式就是熟悉的main
函式。
3、isolate之間的通訊原理
通過前面一節,知道了Dart
是如何建立一個新的Isolate
物件的。但也還是省略了很多東西的,比如子Isolate
通知父Isolate
的原理,也就是Isolate
間的通訊原理。
3.1、ReceivePort與SendPort
在Isolate
給另外一個Isolate
傳送訊息之前,需要先來熟悉ReceivePort
及SendPort
。程式碼如下。
abstract class ReceivePort implements Stream {
//宣告外部實現
external factory ReceivePort();
}
//在isolate_patch.dart中
@patch
class ReceivePort {
@patch
factory ReceivePort() => new _ReceivePortImpl();
@patch
factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) {
return new _ReceivePortImpl.fromRawReceivePort(rawPort);
}
}
class _ReceivePortImpl extends Stream implements ReceivePort {
_ReceivePortImpl() : this.fromRawReceivePort(new RawReceivePort());
_ReceivePortImpl.fromRawReceivePort(this._rawPort) {
_controller = new StreamController(onCancel: close, sync: true);
_rawPort.handler = _controller.add;
}
//返回一個SendPort物件
SendPort get sendPort {
return _rawPort.sendPort;
}
//監聽傳送的訊息
StreamSubscription listen(void onData(var message),
{Function onError, void onDone(), bool cancelOnError}) {
return _controller.stream.listen(onData,
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
}
...
}
@patch
class RawReceivePort {
@patch
factory RawReceivePort([Function handler]) {
_RawReceivePortImpl result = new _RawReceivePortImpl();
result.handler = handler;
return result;
}
}
@pragma("vm:entry-point")
class _RawReceivePortImpl implements RawReceivePort {
factory _RawReceivePortImpl() native "RawReceivePortImpl_factory";
...
SendPort get sendPort {
return _get_sendport();
}
...
/**** Internal implementation details ****/
_get_id() native "RawReceivePortImpl_get_id";
_get_sendport() native "RawReceivePortImpl_get_sendport";
...
}
複製程式碼
在程式碼中,一個ReceivePort
物件包含一個RawReceivePort
物件及SendPort
物件。其中RawReceivePort
物件是在虛擬機器中建立的,它對應著虛擬機器中的ReceivePort
類。程式碼如下。
[->third_party/dart/runtime/lib.isolate.cc]
DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 0, 1) {
ASSERT(
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
//建立一個Entry物件並返回一個埠號。
Dart_Port port_id = PortMap::CreatePort(isolate->message_handler());
//建立ReceivePort物件
return ReceivePort::New(port_id, false /* not control port */);
}
複製程式碼
在建立ReceivePort
物件物件之前,首先會將當前Isolate
中的MessageHandler
物件新增到map中。這裡是一個全域性的map,在Dart VM初始化的時候建立,每個元素都是一個Entry
物件,在Entry
中,有一個MessageHandler
物件,一個埠號及該埠的狀態。
typedef struct {
//埠號
Dart_Port port;
//訊息處理器
MessageHandler* handler;
//埠號狀態
PortState state;
} Entry;
複製程式碼
[->third_party/dart/runtime/vm/port.cc]
Dart_Port PortMap::CreatePort(MessageHandler* handler) {
...
Entry entry;
//分配一個埠號
entry.port = AllocatePort();
//設定訊息處理器
entry.handler = handler;
//埠號狀態
entry.state = kNewPort;
//查詢當前entry的位置
intptr_t index = entry.port % capacity_;
Entry cur = map_[index];
// Stop the search at the first found unused (free or deleted) slot.
//找到空閒或將要被刪除的Entry。
while (cur.port != 0) {
index = (index + 1) % capacity_;
cur = map_[index];
}
if (map_[index].handler == deleted_entry_) {
// Consuming a deleted entry.
deleted_--;
}
//插入到map中
map_[index] = entry;
// Increment number of used slots and grow if necessary.
used_++;
//檢查是否需要擴容
MaintainInvariants();
...
//返回埠號
return entry.port;
}
複製程式碼
注意: 這裡的map的初始容量是8,當達到容量的3/4時,會進行擴容,新的容量是舊的容量2倍。熟悉Java的就知道,這跟HashMap
類似,初始容量為8,載入因子為0.75,擴容是指數級增長。
再來看ReceivePort
物件的建立。
[->third_party/dart/runtime/vm/object.cc]
RawReceivePort* ReceivePort::New(Dart_Port id,
bool is_control_port,
Heap::Space space) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const SendPort& send_port =
//建立SendPort物件
SendPort::Handle(zone, SendPort::New(id, thread->isolate()->origin_id()));
ReceivePort& result = ReceivePort::Handle(zone);
{
//建立ReceivePort物件
RawObject* raw = Object::Allocate(ReceivePort::kClassId,//classId
ReceivePort::InstanceSize(),//物件大小
space);
NoSafepointScope no_safepoint;
result ^= raw;
result.StorePointer(&result.raw_ptr()->send_port_, send_port.raw());
}
if (is_control_port) {
//更新埠的狀態,設為kControlPort
PortMap::SetPortState(id, PortMap::kControlPort);
} else {
//更新埠的狀態,設為kLivePort
PortMap::SetPortState(id, PortMap::kLivePort);
}
return result.raw();
}
複製程式碼
[->third_party/dart/runtime/vm/object.cc]
RawSendPort* SendPort::New(Dart_Port id,
Dart_Port origin_id,
Heap::Space space) {
SendPort& result = SendPort::Handle();
{
//建立SendPort物件
RawObject* raw =
Object::Allocate(SendPort::kClassId, //classId
SendPort::InstanceSize(), //物件ID
space);
NoSafepointScope no_safepoint;
result ^= raw;
result.StoreNonPointer(&result.raw_ptr()->id_, id);
result.StoreNonPointer(&result.raw_ptr()->origin_id_, origin_id);
}
return result.raw();
}
複製程式碼
這裡建立物件時傳遞的classId是在Isolate
物件初始化時註冊的,然後根據該classId來建立相應的物件。在這裡,ReceivePort
對應著Dart SDK中的_RawReceivePortImpl
物件,SendPort
對應著Dart SDK中的_SendPortImpl
物件。
也就是當建立ReceivePort
物件時,會通過Dart VM來建立對應的_RawReceivePortImpl
物件及SendPort
對應的_SendPortImpl
物件。
3.2、isolate間通訊
當ReceivePort
建立成功後,就可以通過呼叫_SendPortImpl
的send
函式來傳送訊息。
@pragma("vm:entry-point")
class _SendPortImpl implements SendPort {
...
/*--- public interface ---*/
@pragma("vm:entry-point", "call")
void send(var message) {
_sendInternal(message);
}
...
// Forward the implementation of sending messages to the VM.
void _sendInternal(var message) native "SendPortImpl_sendInternal_";
}
複製程式碼
_sendInternal
的具體實現在Dart VM中。
[->third_party/dart/runtime/lib/isolate.cc]
DEFINE_NATIVE_ENTRY(SendPortImpl_sendInternal_, 0, 2) {
...
//目標Isolate所對應埠號
const Dart_Port destination_port_id = port.Id();
const bool can_send_any_object = isolate->origin_id() == port.origin_id();
if (ApiObjectConverter::CanConvert(obj.raw())) {//如果傳送訊息為null或者傳送訊息不是堆物件
PortMap::PostMessage(
Message::New(destination_port_id, obj.raw(), Message::kNormalPriority));
} else {
//建立一個MessageWriter物件——writer
MessageWriter writer(can_send_any_object);
// TODO(turnidge): Throw an exception when the return value is false?
PortMap::PostMessage(writer.WriteMessage(obj, destination_port_id,
Message::kNormalPriority));
}
return Object::null();
}
複製程式碼
[->third_party/dart/runtime/vm/port.cc]
bool PortMap::PostMessage(std::unique_ptr<Message> message,
bool before_events) {
MutexLocker ml(mutex_);
//在map中根據目標埠號尋找Entry所在的位置
intptr_t index = FindPort(message->dest_port());
if (index < 0) {
return false;
}
//從map中拿到Entry物件並取出MessageHandler物件
MessageHandler* handler = map_[index].handler;
//這裡的handler是目標Isolate中的MessageHandler
handler->PostMessage(std::move(message), before_events);
return true;
}
複製程式碼
到這裡就已經成功將訊息加入到了目標Isolate
的MessageHandler
中,成功完成了Isolate
間訊息的傳遞,但還尚未對訊息進行處理。
再來看Isolate
對於訊息的處理。
[->third_party/dart/runtime/vm/message_handler.cc]
void MessageHandler::PostMessage(std::unique_ptr<Message> message,
bool before_events) {
Message::Priority saved_priority;
{
MonitorLocker ml(&monitor_);
...
saved_priority = message->priority();
if (message->IsOOB()) {
//加入到OOB型別訊息的佇列中
oob_queue_->Enqueue(std::move(message), before_events);
} else {
//加入到普通訊息佇列中
queue_->Enqueue(std::move(message), before_events);
}
if (paused_for_messages_) {
ml.Notify();
}
if (pool_ != nullptr && !task_running_) {
task_running_ = true;
//非同步處理
const bool launched_successfully = pool_->Run<MessageHandlerTask>(this);
}
}
// Invoke any custom message notification.
//如果自定義了訊息通知函式,那麼在訊息處理完畢後會呼叫該函式
MessageNotify(saved_priority);
}
複製程式碼
在PostMessage
中主要是做了以下操作。
- 根據訊息級別將訊息加入到不同的佇列中。主要有OOB訊息及普通訊息兩個級別,OOB訊息在佇列
oob_queue_
中,普通訊息在佇列queue_
中。OOB訊息級別高於普通訊息,會立即處理。 - 將一個訊息處理任務
MessageHandlerTask
加入到執行緒中。
這裡的執行緒池是在Dart VM建立的時候建立的,在Isolate
執行時傳遞給MessageHandler
的。
下面再來看MessageHandlerTask
,在MessageHandlerTask
的run
函式中執行的是TaskCallback
函式。
[->third_party/dart/runtime/vm/message_handler.cc]
void MessageHandler::TaskCallback() {
MessageStatus status = kOK;
bool run_end_callback = false;
bool delete_me = false;
EndCallback end_callback = NULL;
CallbackData callback_data = 0;
{
...
if (status == kOK) {
...
bool handle_messages = true;
while (handle_messages) {
handle_messages = false;
// Handle any pending messages for this message handler.
if (status != kShutdown) {
//處理訊息
status = HandleMessages(&ml, (status == kOK), true);
}
if (status == kOK && HasLivePorts()) {
handle_messages = CheckIfIdleLocked(&ml);
}
}
}
...
}
...
}
複製程式碼
訊息的處理是在HandleMessages
函式中進行的。
[->third_party/dart/runtime/vm/message_handler.cc]
MessageHandler::MessageStatus MessageHandler::HandleMessages(
MonitorLocker* ml,
bool allow_normal_messages,
bool allow_multiple_normal_messages) {
...
//從佇列中獲取一個訊息,優先OOB訊息
std::unique_ptr<Message> message = DequeueMessage(min_priority);
//沒有訊息時退出迴圈,停止訊息的處理
while (message != nullptr) {
//獲取訊息的長度
intptr_t message_len = message->Size();
...
//獲取訊息級別
Message::Priority saved_priority = message->priority();
Dart_Port saved_dest_port = message->dest_port();
MessageStatus status = kOK;
{
DisableIdleTimerScope disable_idle_timer(idle_time_handler);
//訊息的處理
status = HandleMessage(std::move(message));
}
...
//如果是已關閉狀態,將清除OOB型別訊息
if (status == kShutdown) {
ClearOOBQueue();
break;
}
...
//繼續從佇列中獲取訊息
message = DequeueMessage(min_priority);
}
return max_status;
}
複製程式碼
在HandleMessages
函式中會根據訊息的優先順序別來遍歷所有訊息並一一處理,直至處理完畢。具體訊息處理是在HandleMessage
函式中進行的。該函式在其子類IsolateMessageHandler
中實現。
[->third_party/dart/runtime/vm/isolate.cc]
MessageHandler::MessageStatus IsolateMessageHandler::HandleMessage(
std::unique_ptr<Message> message) {
...
//如果是普通訊息
if (!message->IsOOB() && (message->dest_port() != Message::kIllegalPort)) {
//呼叫Dart層的_lookupHandler函式,返回該函式在isolate_patch.dart中
msg_handler = DartLibraryCalls::LookupHandler(message->dest_port());
...
}
...
MessageStatus status = kOK;
if (message->IsOOB()) {//處理OOB訊息
...
} else if (message->dest_port() == Message::kIllegalPort) {//處理OOB訊息,主要是處理延遲OOB訊息
...
} else {//處理普通訊息
...
//呼叫Dart層的_RawReceivePortImpl物件中的_handleMessage函式,該函式在isolate_patch.dart中
const Object& result =
Object::Handle(zone, DartLibraryCalls::HandleMessage(msg_handler, msg));
if (result.IsError()) {
status = ProcessUnhandledException(Error::Cast(result));
} else {
...
}
}
return status;
}
複製程式碼
在這裡先暫時不管OOB訊息的處理,來看普通訊息的處理。
- 首先呼叫Dart SDK中
_RawReceivePortImpl
物件的_lookupHandler
函式,返回一個在建立_RawReceivePortImpl
物件時註冊的一個自定義函式。 - 呼叫Dart SDK中
_RawReceivePortImpl
物件的_handleMessage
函式並傳入1中返回的自定義函式,通過該自定義函式將訊息分發出去。
至此,一個Isolate
就已經成功的向另外一個Isolate
成功傳送並接收訊息。而雙向通訊也很簡單,在父Isolate
中建立一個埠,並在建立子Isolate
時,將這個埠傳遞給子Isolate
。然後在子Isolate
呼叫其入口函式時也建立一個新埠,並通過父Isolate
傳遞過來的埠把子Isolate
建立的埠傳遞給父Isolate
,這樣父Isolate
與子Isolate
分別擁有對方的一個埠號,從而實現了通訊。具體程式碼[見小節1.2]。
4、總結
主要是梳理了純Dart環境中Isolate
的建立、執行及通訊的實現,內容比較多且枯燥。可以發現,Isolate
比Java
、c/c++
中的執行緒複雜多了,比如有自己的堆。當然,Isolate
也不僅僅只有上述的一些功能,還有程式碼的讀取、解析等,後面再一一梳理。
【參考資料】