2013-07-18 53 views
0

所以,这个例子试图给出一个我试图修改的更大的系统(即Orchard CMS)的简单视图。因此,它可能不完美。循环依赖与横切关注


我想创建一个通过设置管理的日志记录系统。我遇到的问题是检索设置会导致记录发生。下面是希望能说明问题一个简单的例子:

static void Main(string[] args) 
{ 
    string[] messages = "this is a test. but it's going to be an issue!".Split(' '); 

    Parallel.ForEach(messages, Log); 

    Console.ReadLine(); 
} 

public static void Log(string message) 
{ 
    Console.WriteLine(GetPrefix() + message); 
} 

public static string GetPrefix() 
{ 
    Log("Getting prefix!"); 
    return "Prefix: "; 
} 

这是一个明显的StackOverflowException。但是,我该如何解决它?我不能只是禁用日志记录,直到我得到GetPrefix的响应,因为我可能会错过日志。 (事实上​​,在这个简单的例子,我想念所有,但第一个。)

static void Main(string[] args) 
{ 
    string[] messages = "this is a test. but it's going to be an issue!".Split(' '); 

    Parallel.ForEach(messages, Log); 

    Console.ReadLine(); 
} 

static bool _disable = false; 
public static void Log(string message) 
{ 
    if (_disable) 
    { 
     return; 
    } 
    _disable = true; 
    Console.WriteLine(GetPrefix() + message); 
    _disable = false; 
} 

public static string GetPrefix() 
{ 
    Log("Getting prefix!"); 
    return "Prefix: "; 
} 

(^坏。)

注意,我目前没有在GetPrefix方法控制,只有Log方法。

我不确定是否有办法解决这个问题;我可能需要将其他设置(如配置或单独的设置文件)。然而,如果任何人有想法或建议,我会很乐意尝试任何事情,因为我宁愿现在离开设置(这是在管理界面中)。

+0

你必须同步对'bool _disable'的访问。你失去了并行执行,这在这个例子中很好,因为无论如何,Console.WriteLine是同步的。 – JosephHirn

+0

@Ginosaji:这是一个简单的例子,但实际上,同步会对性能产生严重影响。 – zimdanen

+0

您仍然可以并行处理这些消息并只是同步日志记录。正如我所说,无论如何,Console.WriteLine是同步的,所以你通过锁定'bool _disable'没有任何损失。 – JosephHirn

回答

0

如何拆分日志方法为:

public static void LogWithPrefix(string message) 
{ 
    var prefix = GetPrefix(); 
    Log(prefix + message); 
} 

public static void Log(string message) 
{ 
    Console.WriteLine(message); 
} 
+0

前缀是必需的。在这种情况下,获取前缀代表获取日志设置。没有这些,我不知道在哪里登录。 – zimdanen

+0

@zimdanen:那么,Log是什么?(“Getting prefix!”);'应该登录到原始示例中? – JayC

+0

@JayC:我想禁用它,所以它不记录任何地方。 – zimdanen

1

所有你需要做的是禁用当前堆栈帧。现在你可以使用反射来遍历堆栈框架,看看它是否被调用,但有一个更简单的方法。每个线程都有一个堆栈框架。因此,使静态变量[ThreadStatic]

[ThreadStatic] static bool _disable = false;

这是如何工作的?

http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx

“指示静态字段的值对于每个线程是唯一的。”

编辑:但仅此可能不够。你想要的是什么可能是每个任务的一个静态变量。现在,由于任务将按照每个线程顺序执行,在这种特殊情况下,我认为这不是问题,除非记录器可能会在未禁用的情况下失败......并且我不确定在这种情况下会发生什么情况,但它可能需要你在一个try/finally块最起码换东西:

static void Main() //Main(string[] args) 
{ 
    string[] messages = "this is a test. but it's going to be an issue!".Split(' '); 

    Parallel.ForEach(messages, Log); 

    Console.ReadLine(); 
} 
[ThreadStatic] 
static bool _disable = false; 
public static void Log(string message) 
{ 
    if (_disable) 
    { 
     return; 
    } 
    try { 
     _disable = true; 
     Console.WriteLine(GetPrefix() + message); 
    } finally { 
     _disable = false; 
    } 
} 

public static string GetPrefix() 
{ 
    Log("Getting prefix!"); 
    return "Prefix: "; 
} 

编辑II:从http://msdn.microsoft.com/en-us/library/dd460712.aspx看来,一旦任何一组任务的罚球任务委托以外的异常,你不能保证执行任何剩余的任务。最好在你的代表中处理这些特殊情况。

+0

+1:这适用于人为的例子。看起来也有[.NET 4.0中的实例字段的等价形式](http://theburningmonk.com/2010/10/threadstatic-vs-threadlocal/)。我会玩这个,看看它的表现如何,并回馈反馈。谢谢! – zimdanen