通过 TChan 广播 BinaryString 时,复制了整个 Binary 还是仅复制了引用?
如果整个二进制文件被复制如何只发送参考?
仅将引用写入TChan,不会复制有效负载。一直复制所有数据效率太低了,而且由于数据是不可变的(通常,您可以作弊),因此仅传输引用是安全的。
比 Daniel 更准确一点(并在他的评论中确认 Daniels 的怀疑):将指向 BinaryString 的构造函数的指针(你的意思是 ByteString 吗?)写入 TVar。
让我们通过检查相关代码来确认。TChan建立在 上TVar,并用于writeTVar写入值,该值在中实现(并由andGHC.Conc.Sync重新导出):GHC.ContControl.Concurrent.STM.TVar
-- |Write the supplied value into a TVar
writeTVar :: TVar a -> a -> STM ()
writeTVar (TVar tvar#) val = STM $ \s1# ->
    case writeTVar# tvar# val s1# of
         s2# -> (# s2#, () #)
参数只是传递给函数writeTVar#,这是一个基本操作,在以下位置实现rts/PrimOps.cmm:
stg_writeTVarzh
{
  W_ trec;
  W_ tvar;
  W_ new_value;
  /* Args: R1 = TVar closure */
  /*       R2 = New value    */
  MAYBE_GC (R1_PTR & R2_PTR, stg_writeTVarzh); // Call to stmWriteTVar may allocate
  trec = StgTSO_trec(CurrentTSO);
  tvar = R1;
  new_value = R2;
  foreign "C" stmWriteTVar(MyCapability() "ptr", trec "ptr", tvar "ptr", new_value "ptr") [];
  jump %ENTRY_CODE(Sp(0));
}
这将以下代码包装在rts/STM.c:
void stmWriteTVar(Capability *cap,
                  StgTRecHeader *trec,
                  StgTVar *tvar, 
                  StgClosure *new_value) {
  StgTRecHeader *entry_in = NULL;
  TRecEntry *entry = NULL;
  TRACE("%p : stmWriteTVar(%p, %p)", trec, tvar, new_value);
  ASSERT (trec != NO_TREC);
  ASSERT (trec -> state == TREC_ACTIVE || 
          trec -> state == TREC_CONDEMNED);
  entry = get_entry_for(trec, tvar, &entry_in);
  if (entry != NULL) {
    if (entry_in == trec) {
      // Entry found in our trec
      entry -> new_value = new_value;
    } else {
      // Entry found in another trec
      TRecEntry *new_entry = get_new_entry(cap, trec);
      new_entry -> tvar = tvar;
      new_entry -> expected_value = entry -> expected_value;
      new_entry -> new_value = new_value;
    } 
  } else {
    // No entry found
    StgClosure *current_value = read_current_value(trec, tvar);
    TRecEntry *new_entry = get_new_entry(cap, trec);
    new_entry -> tvar = tvar;
    new_entry -> expected_value = current_value;
    new_entry -> new_value = new_value;
  }
  TRACE("%p : stmWriteTVar done", trec);
}
在这里,我们看到这new_value是一个从未被查看过的指针,并被如此存储。