讓我回答我的問題。使用DotNetInside反編譯Dataflow程序集的信息,例如,TransformBlock
here(再次感謝@ 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 });
}
...
}
SingleProducerConstrained確實有效果,但僅限於特定情況。例如,在ActionBlock中,該動作必須是同步的才能進行計數。 – i3arnon
在我的情況下,我正在處理同步操作。它是一個沒有異步操作的計算綁定管道。以前的答案[這裏](http://stackoverflow.com/questions/11155085/tpl-dataflow-speedup/11156806#11156806)表明它可以真正幫助吞吐量在這種情況下。 – davidbak