有关背景信息,请参阅此问题:
该问题询问Tasks如何影响Trace.CorrelationManager.ActivityId.@Greg Samson用测试程序回答了他自己的问题,显示ActivityId在Tasks的上下文中是可靠的.测试程序在Task委托的开头设置一个ActivityId,休眠以模拟工作,然后检查最后的ActivityId以确保它是相同的值(即它没有被另一个线程修改).该程序成功运行.
在研究线程,任务和并行操作的其他"上下文"选项(最终为日志提供更好的上下文)时,我遇到了Trace.CorrelationManager.LogicalOperationStack的一个奇怪问题(无论如何我都很奇怪).我在下面的问题中复制了我的"答案".
我认为它充分描述了我遇到的问题(Trace.CorrelationManager.LogicalOperationStack显然已经损坏 - 或者什么 - 当在Parallel.For的上下文中使用时,但只有当Parallel.For本身包含在逻辑操作中时) .
这是我的问题:
Trace.CorrelationManager.LogicalOperationStack应该可以与Parallel.For一起使用吗?如果是这样,如果一个逻辑操作已经与Parallel.For启动有效,它是否会有所不同?
是否有一种"正确"的方式使用LogicalOperationStack与Parallel.For?我能不同地对这个示例程序进行编码以使其"有效"吗?通过"工作",我的意思是LogicalOperationStack总是具有预期的条目数,并且条目本身是预期的条目.
我已经使用Threads和ThreadPool线程做了一些额外的测试,但是我必须返回并重试这些测试,看看我是否遇到了类似的问题.
我会说,看起来任务/并行线程和ThreadPool线程确实从父线程"继承"了Trace.CorrelationManager.ActivityId和Trace.CorrelationManager.LogicalOperationStack值.这是预期的,因为CorrelationManager使用CallContext的LogicalSetData方法(而不是SetData)存储这些值.
请再次参考此问题,以获取我在下面发布的"答案"的原始背景:
另请参阅Microsoft的Parallel Extensions论坛上的类似问题(目前尚未得到解答):
[开始粘贴]
请原谅我发布这个作为答案,因为它不是你的问题的真正答案,但是,它与你的问题有关,因为它处理CorrelationManager行为和线程/任务/等.我一直在寻找使用CorrelationManager LogicalOperationStack(和StartLogicalOperation/StopLogicalOperation方法)在多线程场景中提供额外的上下文.
我拿了你的例子并稍微修改它以增加使用Parallel.For并行执行工作的能力.另外,我用StartLogicalOperation/StopLogicalOperation括号(内部)DoLongRunningWork.从概念上讲,DoLongRunningWork每次执行时都会执行以下操作:
DoLongRunningWork
StartLogicalOperation
Thread.Sleep(3000)
StopLogicalOperation
Run Code Online (Sandbox Code Playgroud)
我发现如果我将这些逻辑操作添加到您的代码中(或多或少),所有逻辑操作都保持同步(始终是堆栈上预期的操作数,并且堆栈上的操作值始终为预期).
在我自己的一些测试中,我发现并非总是这样.逻辑操作堆栈正在"损坏".我能想到的最好的解释是,当"子"线程退出时,将CallContext信息"合并"回"父"线程上下文导致"旧"子线程上下文信息(逻辑操作)为"继承"由另一个兄弟姐妹线程.
问题也可能与Parallel.For显然使用主线程(至少在示例代码中,如编写)作为"工作线程"之一(或者在并行域中应该调用它们)之间的事实有关.每当执行DoLongRunningWork时,就会启动一个新的逻辑操作(在开始时)并停止(在结束时)(也就是说,将其推送到LogicalOperationStack并从中弹出).如果主线程已经有效的逻辑操作,并且DoLongRunningWork在主线程上执行,则启动新的逻辑操作,因此主线程的LogicalOperationStack现在具有两个操作.DoLongRunningWork的任何后续执行(只要DoLongRunningWork的这个"迭代"在主线程上执行)将(显然)继承主线程的LogicalOperationStack(现在它有两个操作,而不仅仅是一个预期的操作).
我花了很长时间才弄清楚为什么LogicalOperationStack的行为在我的示例中与我的示例的修改版本不同.最后我看到在我的代码中我将整个程序放在逻辑操作中,而在我的测试程序的修改版本中,我没有.这意味着在我的测试程序中,每次执行"工作"(类似于DoLongRunningWork)时,已经存在逻辑操作.在我的测试程序的修改版本中,我没有在逻辑操作中将整个程序括起来.
所以,当我修改你的测试程序以在逻辑操作中包含整个程序时如果我使用Parallel.For,我遇到了完全相同的问题.
使用上面的概念模型,这将成功运行:
Parallel.For
DoLongRunningWork
StartLogicalOperation
Sleep(3000)
StopLogicalOperation
Run Code Online (Sandbox Code Playgroud)
虽然这最终会因为LogicalOperationStack显然不同步而断言:
StartLogicalOperation
Parallel.For
DoLongRunningWork
StartLogicalOperation
Sleep(3000)
StopLogicalOperation
StopLogicalOperation
Run Code Online (Sandbox Code Playgroud)
这是我的示例程序.它类似于你的,因为它有一个DoLongRunningWork方法来操作ActivityId以及LogicalOperationStack.我也有两种踢DoLongRunningWork的方式.一种风味使用任务一使用Parallel.For.还可以执行每种风格,使得整个并行操作被包含在逻辑操作中或不包含在逻辑操作中.因此,总共有4种方法来执行并行操作.要尝试每个,只需取消注释所需的"使用..."方法,重新编译并运行. UseTasks,UseTasks(true)并且UseParallelFor应该全部运行完成. UseParallelFor(true)因为LogicalOperationStack没有预期的条目数,所以会在某些时候断言.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; …Run Code Online (Sandbox Code Playgroud) .net c# system.diagnostics parallel-extensions task-parallel-library
我正在实现一些基于点列表的数学算法,如距离,面积,质心等.就像在这篇文章中一样:找到使用linq导航点列表所需的距离
该职位介绍如何通过基本上压缩和解序列"与自身",由1偏移的原始的IEnumerable的开始位置生成用于拉链的序列来计算点的序列(按顺序取)的总距离.
因此,考虑到在.NET 4.0中的zip扩展,假设点的点类型,以及合理的距离公式,你可以拨打电话这样从一个点到下一个,然后生成距离的顺序来总结的距离:
var distances = points.Zip(points.Skip(1),Distance);
double totalDistance = distances.Sum();
Run Code Online (Sandbox Code Playgroud)
面积和质心计算类似,因为它们需要迭代序列,处理每对点(点[i]和点[i + 1]).我想过制作一个通用的IEnumerable扩展,适合实现这些(可能还有其他)算法,这些算法在序列上运行,一次取两个项目(points [0]和points [1],points [1]和points [2], ...,点[n-1]和points [n](或者是n-2和n-1 ......)并应用函数.
我的通用迭代器将具有与Zip类似的签名,但它不会收到第二个要压缩的序列,因为它实际上只是自己压缩.
我的第一次尝试看起来像这样:
public static IEnumerable<TResult> ZipMyself<TSequence, TResult>(this IEnumerable<TSequence> seq, Func<TSequence, TSequence, TResult> resultSelector)
{
return seq.Zip(seq.Skip(1),resultSelector);
}
Run Code Online (Sandbox Code Playgroud)
开始编辑: 在看到响应后,我已经实现了Pairwise,并明确使用了底层的Enumerator,如下所示:
public static IEnumerable<TResult> Pairwise<TSequence, TResult>(this IEnumerable<TSequence> seq, Func<TSequence, TSequence, TResult> resultSelector)
{
TSequence prev = default(TSequence);
using (IEnumerator<TSequence> e = seq.GetEnumerator())
{
if (e.MoveNext()) prev = e.Current;
while (e.MoveNext()) yield return resultSelector(prev, prev = e.Current);
}
}
Run Code Online (Sandbox Code Playgroud)
虽然肯定比我的初始版本更复杂,但是这一次迭代输入序列一次而原始迭代两次. …
企业库的日志记录应用程序块中的LogEntry.cs中存在以下代码:
private bool UnmanagedCodePermissionAvailable
{
get
{
if (!unmanagedCodePermissionAvailableInitialized)
{
// check whether the unmanaged code permission is available to avoid three potential stack walks
bool internalUnmanagedCodePermissionAvailable = false;
SecurityPermission unmanagedCodePermission =
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
// avoid a stack walk by checking for the permission on the current assembly. this is safe because there are no
// stack walk modifiers before the call.
if (SecurityManager.IsGranted(unmanagedCodePermission))
{
try
{
unmanagedCodePermission.Demand();
internalUnmanagedCodePermissionAvailable = true;
}
catch (SecurityException)
{ }
}
this.UnmanagedCodePermissionAvailable =
internalUnmanagedCodePermissionAvailable; …Run Code Online (Sandbox Code Playgroud) 是否可以创建一个允许配置"索引"值的log4net自定义PatternLayoutConverter?我知道"属性"转换字符串,它允许您编写如下代码:
ThreadContext.Properties["ID"] = yourID;
Run Code Online (Sandbox Code Playgroud)
并指定如下:
%property{ID}
Run Code Online (Sandbox Code Playgroud)
该值应包含在输出中.
如果我想记录的值在其他"字典"中怎么办?我想我可以编写一些逻辑来将这些值从字典复制到log4net上下文之一,然后只使用内置的%property令牌.如果我希望log4net根据配置文件中指定的索引值直接从我自己的"字典"中记录值,该怎么办?
我可以编写自己的PatternLayoutConverter,允许我配置如下内容:
%myproperty{ID}
Run Code Online (Sandbox Code Playgroud)
然后从我自己的"字典"中提取相应的"ID"值?
对于任何有兴趣的人来说,用NLog做同样的事情很容易:
[LayoutRenderer("MyGDC")]
class GdcLayoutRenderer : LayoutRenderer
{
[RequiredParameter]
[DefaultParameter]
public string Item { get; set; }
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
string msg = GDC.Get(this.Item);
builder.Append(msg);
}
protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
{
return 10;
}
}
Run Code Online (Sandbox Code Playgroud)
并配置如下:
告诉NLog任何带扩展名的程序集:
<extensions>
<add assembly="NLog.Extensions"/>
</extensions>
Run Code Online (Sandbox Code Playgroud)
在布局中使用"indexed"属性:
<layout="${longdate} | ${MyGDC:item=name} | ${message}"/>
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我实际上使用NLog的GDC对象作为我的"字典",但我演示了如何编写自己的"可索引"LayoutRenderer(或多或少等同于log4net的PatternLayoutConverter)来访问由值中的值索引的值.配置文件.
[编辑]我得到了我想要的答案.我在这里包含了我的示例PatternLayoutRenderer的代码.在我的测试中,我在我的主窗体类中有一个静态字典,我可以存储"应用程序设置".我创建了一个PatternLayoutConverter,可以接受一个键作为参数,以便转换器可以在字典中查找正确的值.我可能能够使用log4net(或NLog)上下文对象实现相同的功能,但在我们的应用程序中,我们可能会有一些应用程序将用于其他目的的设置或会话信息,我们希望能够将其添加到记录输出.由于它已经在查找结构中,因此能够直接引用数据而不必将其显式复制到log4net(或NLog上下文)会很好.
无论如何,这是代码:
namespace Log4NetTest
{
class KeyLookupPatternConverter : PatternLayoutConverter
{
protected override void Convert(System.IO.TextWriter …Run Code Online (Sandbox Code Playgroud) 在我的应用程序中,我有绑定到TextBoxes的数字(double或int)ViewModel属性.ViewModel实现IDataErrorInfo以检查输入的值是否落在"业务逻辑"的可接受范围内(例如,高度不能为负值).我每页都有一些TextBox,并且有一个按钮(在向导中称为"next"),启用属性绑定到ViewModel布尔值,该布尔值指定整个页面上是否有任何错误.根据我编写的IDataErrorInfo规则,使用有效/无效值正确更新按钮的启用/禁用状态.
但是,由于输入值没有转换(即"12bd39"不是有效的双精度),因此无法让我的viewmodel知道何时抛出异常,因此在转换异常的情况下我的'next'按钮尽管输入错误,仍会保持启用 然而,由于我的绑定,GUI正确地反映了装饰者的错误:
<TextBox Text="{Binding Temperature, Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
Run Code Online (Sandbox Code Playgroud)
如何让视图知道发生了'ValidatesOnExceptions'样式错误.Josh Smith在这里的看法似乎依赖于使每个ViewModel属性成为一个字符串并滚动自己的异常检查,这似乎是很多额外的工作.我还开始寻找卡尔Shifflett的实现在这里,但我似乎无法捕捉到的路由事件把这个代码到视图的代码隐藏文件时,我会想到:
public ViewClass()
{
this.InitializeComponent();
this.AddHandler(System.Windows.Controls.Validation.ErrorEvent, new RoutedEventHandler(ValidationErrorHandler));
}
private void ValidationErrorHandler(object sender, RoutedEventArgs e)
{
var blah = e as System.Windows.Controls.ValidationErrorEventArgs;
if (blah.Action == ValidationErrorEventAction.Added)
{
}
else if (blah.Action == ValidationErrorEventAction.Removed)
{
}
}
Run Code Online (Sandbox Code Playgroud)
Silverlight似乎也有一个你可以订阅的事件,但我找不到WPF(3.5)中的确切等价物.任何帮助表示赞赏!
在我的app.config中,我想设置3个跟踪级别(交换机?):详细,警告和无.在代码的调试版本中,我想要在我想要警告的版本中激活详细开关.在特殊情况下,我的应用程序用户可以修改配置文件以禁用所有跟踪.
我希望在控制台上输出调试跟踪,而发布只跟踪到日志文件.
我写了以下内容:
[...]
<system.diagnostics>
<sources>
<!-- This section defines the logging configuration for My.Application.Log -->
<source name="debug" switchName="debug">
<listeners>
<add name="FileLog"/>
<add name="console"/>
</listeners>
</source>
<source name="release" switchName="release">
<listeners>
<add name="FileLog"/>
</listeners>
</source>
<source name="silent" switchName="none">
<listeners/>
</source>
</sources>
<switches>
<add name="debug" value="Verbose"/>
<add name="release" value="Warning"/>
<add name="none" value="Off"/>
</switches>
<!--<sharedListeners>
<add name="FileLog" type="System.Diagnostics.TextWriterTraceListener" traceOutputOptions="DateTime" initializeData="felix.log"/>
<add name="console" type="System.Diagnostics.ConsoleTraceListener" initializeData="false" />
</sharedListeners>-->
<trace autoflush="false" indentsize="4">
<listeners>
<add name="FileLog" type="System.Diagnostics.TextWriterTraceListener" traceOutputOptions="DateTime" initializeData="felix.log"/>
<add name="console" type="System.Diagnostics.ConsoleTraceListener" initializeData="false"/>
<remove name="Default"/>
</listeners>
</trace> …Run Code Online (Sandbox Code Playgroud) 我有一个项目,使用System.Diagnostics进行日志记录,
它创建了许多新的日志文件,每个文件以GUID开头,
即使最后一个日志文件非常小
我想设置一个控制新日志文件创建的角色
我在哪里可以配置它?
第二个问题:我在哪里可以设置日志写非utc时间?
谢谢
最近我一直致力于一个项目,其中包括我们想要提供一个集中配置系统.我们使用WCF,Silverlight,C#等来创建分布式服务和客户端系统.我们要配置的一件事是记录.显然,我们可以通过app.config或单独的日志配置文件配置log4net或NLog.我们也可以通过代码配置.我想看看是否可以通过代码从XML进行配置.换句话说,假设您在内存中(可能从数据库中读取?)配置任一日志框架所需的整个XML.可以吗?是否可以通过包含正确形成的字符串(在特定日志框架的上下文中)配置log4net和/或NLog,而不是从文件读取或通过"
我已经想出了如何为每个这些日志框架做到这一点.我不确定我们是否真的会使用它,但我认为我会在这里分享它,以防万一其他人可能会发现它有用.另外,请随意评论以这种方式配置日志框架的可行性(或不可行性).
我能想到的两个明显的潜在问题是:
构造有效的XML(或在数据库中输入)可能很困难.我的第一个猜测是,人们将以与今天相同的方式定义XML.将它放在app.config(或外部配置)文件中,然后运行测试程序以验证XML是否产生预期结果.
更新数据库中的XML然后让程序/服务/对变化作出反应(比如使用log4net的ConfigureAndWatch选项)是多么容易或困难(或不可能)?我对程序或服务如何知道XML已更新的机制不感兴趣.我们假设程序将定期检查数据库.给定一个新的XML字符串,很容易重新配置日志框架.
我将发布我的技术作为这个问题的答案.
我们正在经历将产品代码库从Java 8升级到Java 12的过程。发现的一个问题是,我们的代码在很多情况下都使用下划线字符(_)作为变量名,不再允许使用(显然是从Java 9开始)。这是遗留代码,所以我真的不知道为什么要这样写。在绝大多数情况下,似乎已经定义了一种方法(名为_)来按名称检索资源字符串。例如,这种方法的一个实例如下所示:
private static String _(String key)
{
return PTR.getResources ().getStringProperty (key);
}
Run Code Online (Sandbox Code Playgroud)
该方法的用法如下:
JFileChooser chooser = m_directory.getFileChooser ();
chooser.setDialogTitle (_("chooser.title"));
chooser.setFileFilter (ExtensionsFileFilter.withFullDescription (_("chooser.shp"), ".shp"));
chooser.setFileSelectionMode (JFileChooser.FILES_AND_DIRECTORIES);
addProperty (_("labels.dir"), m_directory);
Run Code Online (Sandbox Code Playgroud)
我们正在重命名_方法。但是,我很好奇为什么在我们的代码中使用了这种模式。这是某个时候流行的模式吗?使用某种技术(Swing)时它受欢迎吗?到目前为止,我所有的Google都只因为变量不能再被命名为_而大获成功,但是却没有解释为什么首先要这样做。原来的开发人员已经不在了,所以我不能问他们。
有人有什么想法吗?
我认为这不是所建议问题的重复。该问题标记为“ c”,而我的标记为“ java”。同样,该问题的可接受答案表示_函数是gettext提供的预定义函数。这不适用于我,因为我要询问的_函数实际上是在我们的Java代码库中定义的。话虽如此,建议的问题和此处发布的一些信息的上下文似乎表明存在关联。听起来_函数/方法通常可以理解为在检索可本地化的字符串资源时使用。
请注意,我在SO上看到了这些问题(讨论了log4net的线程安全性),我怀疑他们回答了我的问题,但我还是会问:
最近我写了一个用于日志记录的WCF服务.这个想法非常类似于Clog(或者在Calcium下寻找Clog).基本上,我已经实现了一个用于Silverlight客户端(Silverlight类库)的日志API.日志记录API或多或少是我们在应用程序中的其他地方使用的Common.Logging for .NET API的克隆.API的实现将所有日志记录消息转发到WCF日志记录服务,该服务本身是根据Common.Logging实现的.
在看Clog的时候,我在Log4NetStrategy课堂上发现了以下代码让我觉得有些奇怪:
/// <summary>
/// All Write log calls are done asynchronously because the DanielVaughan.Logging.Log
/// uses the AppPool to dispatch calls to this method. Therefore we need to ensure
/// that the call to Log is threadsafe. That is, if an appender such as FileAppender is used,
/// then we need to ensure it is called from no more than one thread at a …Run Code Online (Sandbox Code Playgroud)