2014-06-28 34 views
3

...並使其生效?在TPL數據流中,是否可以在塊創建之後但使用之前更改DataflowBlockOptions?

我想推遲設置ExecutionDataflowBlockOptions.SingleProducerConstrained屬性,直到我準備好將網絡連接在一起。 (因爲我想分開創建塊和它們的語義,將網絡連接在一起並與其語義相關聯。)

但是據我所知,只能在創建塊時設置ExecutionDataflowBlockOptions(例如,對於TransformBlock,TransformManyBlock等,您將它傳遞給構造函數,否則不可見)。

但是......它沒有逃脫我的通知,該屬性有公共setter。所以......我可以使用ExecutionDataflowBlockOptions的佔位符實例創建塊並保留它,以便稍後可以設置SingleProducerConstrained = true,如果我希望將塊連接在一起(並且它會生效)?

(順便說一句,有沒有辦法判斷SingleProducerConstrained是具有比測量吞吐量等有什麼影響?)

更新: @ i3amon在他的回答正確地指出了這一點,不能因爲數據流塊完成克隆你傳入並使用它的DataflowBlockOptions。但我仍然使用內部數據結構,我可以通過反射和動態訪問。我在下面回答了這個問題。

+0

SingleProducerConstrained確實有效果,但僅限於特定情況。例如,在ActionBlock中,該動作必須是同步的才能進行計數。 – i3arnon

+0

在我的情況下,我正在處理同步操作。它是一個沒有異步操作的計算綁定管道。以前的答案[這裏](http://stackoverflow.com/questions/11155085/tpl-dataflow-speedup/11156806#11156806)表明它可以真正幫助吞吐量在這種情況下。 – davidbak

回答

1

讓我回答我的問題。使用DotNetInside反編譯Dataflow程序集的信息,例如,TransformBlockhere(再次感謝@ i3amon爲dotnetinside.com的鏈接),以及非常好的ExposedObject程序包在codeplex here(我在this blog post上了解到這一點,我做了以下工作:

  • 的TPL數據流塊中的所有執行經由DebuggerTypeProxy屬性,該屬性,施加到一個類型,名稱另一種類型在Visual Studio調試器使用只要原來的類型是將被顯示調試器可視化工具(例如,觀看窗口)

  • 其中每個DebuggerTypeProxy命名的類是屬性附加到的數據流塊的內部類,通常名爲DebugView。那個班總是私密的。它揭示了關於數據流塊的很多很酷的東西,包括它的真正(不是副本)DataflowBlockOptions,以及如果塊是源塊,則可以使用ITargetBlock[]在構建之後從其開始塊跟蹤數據流網絡。

  • 一旦你獲得了DebugView的實例,您可以通過ExposedObject使用dynamic得到任何由類公開的屬性 - ExposedObject讓你把一個對象,並用普通的方法和屬性語法來訪問其方法和屬性。

  • 因此,你可以得到DataflowBlockOptions出來的數據流塊並改變其NameFormat,如果它是一個ExecutionDataflowBlockOptions(你還沒有迷上了塊到其他塊),你可以改變它的SingleProducerConstrained價值。

  • 但是,您不能使用dynamic來查找或構造內部DebugView類的實例。你需要反思。您首先獲取數據流塊類型的DebuggerTypeProxy屬性,獲取調試類的名稱,假設它是數據流塊類型的內部類 ,並搜索它,將其轉換爲封閉的泛型類型,最後將其轉換爲 構造一個實例。

  • 請充分意識到您正在使用數據流內部未公開的代碼。使用你自己的 判斷這是否是一個好主意。在我看來,TPL Dataflow的開發人員在調試器中支持查看這些塊做了很多工作,他們可能會繼續。細節可能會改變,但是,如果您正在對反射和這些類型的動態使用進行適當的錯誤檢查,您將能夠發現代碼何時停止使用新版本的TPL Dataflow。

下面的代碼片段可能不編譯在一起 - 他們只是簡單地剪切粘貼&出我的工作代碼,來自不同班級,但他們肯定會給你的想法。我做得很好。 (另外,爲了簡潔起見,我忽略了所有錯誤檢查。)(另外,我僅在TPL數據流的版本4.5.20.0中開發/測試了此代碼,因此您可能必須適應過去版本或未來版本。)

// Set (change) the NameFormat of a dataflow block after construction 
public void SetNameFormat(IDataflowBlock block, string nameFormat) 
{ 
    try 
    { 
     dynamic debugView = block.GetInternalData(Logger); 
     if (null != debugView) 
     { 
      var blockOptions = debugView.DataflowBlockOptions as DataflowBlockOptions; 
      blockOptions.NameFormat = nameFormat; 
     } 
    } 
    catch (Exception ex) 
    { 
     ... 
    } 
} 

// Get access to the internal data of a dataflow block via its DebugTypeProxy class 
public static dynamic GetInternalData(this IDataflowBlock block) 
{ 
    Type blockType = block.GetType(); 
    try 
    { 
     // Get the DebuggerTypeProxy attribute, which names the debug class type. 
     DebuggerTypeProxyAttribute debuggerTypeProxyAttr = 
      blockType.GetCustomAttributes(true).OfType<DebuggerTypeProxyAttribute>().Single(); 

     // Get the name of the debug class type 
     string debuggerTypeProxyNestedClassName = 
      GetNestedTypeNameFromTypeProxyName(debuggerTypeProxyAttr.ProxyTypeName); 

     // Get the actual Type of the nested class type (it will be open generic) 
     Type openDebuggerTypeProxyNestedClass = blockType.GetNestedType(
      debuggerTypeProxyNestedClassName, 
      System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic); 

     // Close it with the actual type arguments from the outer (dataflow block) Type. 
     Type debuggerTypeProxyNestedClass = 
      openDebuggerTypeProxyNestedClass.CloseNestedTypeOfClosedGeneric(blockType); 

     // Now create an instance of the debug class directed at the given dataflow block. 
     dynamic debugView = ExposedObject.New(debuggerTypeProxyNestedClass, block); 

     return debugView; 
    } 
    catch (Exception ex) 
    { 
     ... 
     return null; 
    } 
} 

// Given a (Type of a) (open) inner class of a generic class, return the (Type 
// of the) closed inner class. 
public static Type CloseNestedTypeOfClosedGeneric(
         this Type openNestedType, 
         Type closedOuterGenericType) 
{ 
    Type[] outerGenericTypeArguments = closedOuterGenericType.GetGenericArguments(); 
    Type closedNestedType = openNestedType.MakeGenericType(outerGenericTypeArguments); 
    return closedNestedType; 
} 

// A cheesy helper to pull a type name for a nested type out of a full assembly name. 
private static string GetNestedTypeNameFromTypeProxyName(string value) 
{ 
    // Expecting it to have the following form: full assembly name, e.g., 
    // "System.Threading...FooBlock`1+NESTEDNAMEHERE, System..." 
    Match m = Regex.Match(value, @"^.*`\d+[+]([_\w-[0-9]][_\w]+),.*$", RegexOptions.IgnoreCase); 
    if (!m.Success) 
     return null; 
    else 
     return m.Groups[1].Value; 
} 
// Added to IgorO.ExposedObjectProject.ExposedObject class to let me construct an 
// object using a constructor with an argument. 
public ExposedObject { 
    ... 

    public static dynamic New(Type type, object arg) 
    { 
     return new ExposedObject(Create(type, arg)); 
    } 

    private static object Create(Type type, object arg) 
    { 
     // Create instance using Activator 
     object res = Activator.CreateInstance(type, arg); 
     return res; 

     // ... or, alternatively, this works using reflection, your choice: 
     Type argType = arg.GetType(); 
     ConstructorInfo constructorInfo = GetConstructorInfo(type, argType); 
     return constructorInfo.Invoke(new object[] { arg }); 
    } 
    ... 
} 
3

這是不可能的。事後修改選項將不起作用。這些選項被克隆在塊的構造函數中。稍後更改選項將不起作用。

你可以看到,herehere的例子,它是簡單的驗證:

var options = new ExecutionDataflowBlockOptions 
{ 
    NameFormat = "bar", 
}; 
var block = new ActionBlock<int>(_ => { }, options); 

options.NameFormat = "hamster"; 
Console.WriteLine(block.ToString()); 

輸出:

酒吧

+1

再次感謝i3amon。事實上,就在看到你的答案之前,我只是看着[dotnetinside.com](http://dotnetinside.com/en/type/System.Threading.Tasks.Dataflow/TransformBlock%3CTInput%2C+TOutput%3E/4.5。 20.0)(你在回答我的最後一個問題時教會了我),並發現它被克隆了。 – davidbak

相關問題