如何使用异步管理一个NDC样log4net的堆栈/ await方法? (每个任务堆栈?) [英] how to manage an NDC-like log4net stack with async/await methods? (per-Task stack?)

查看:128
本文介绍了如何使用异步管理一个NDC样log4net的堆栈/ await方法? (每个任务堆栈?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个正常/同步/单线程控制台应用程序,NDC.Push工作正常管理当前项目(可能在多层嵌套,但是在这个例子只是1级)。

In a normal/synchronous/single-threaded console app, NDC.Push works fine for managing the 'current item' (potentially at multiple levels of nesting, but just 1 level for this example).

例如:

private static ILog s_logger = LogManager.GetLogger("Program");

static void Main(string[] args)
{
    BasicConfigurator.Configure();

    DoSomeWork("chunk 1");
    DoSomeWork("chunk 2");
    DoSomeWork("chunk 3");
}

static void DoSomeWork(string chunkName)
{
    using (NDC.Push(chunkName))
    {
        s_logger.Info("Starting to do work");
        Thread.Sleep(5000);
        s_logger.Info("Finishing work");
    }
}

这会导致期望日志输出,呈现出​​块XNDC条目只是纲要(为基本配置器的默认图案)

This will result in the expect log output, showing a 'chunk X' NDC entry just to the right of 'Program' (the default pattern for the basic configurator)

232 [9] info程序块1 - 开始做的工作。

232 [9] INFO Program chunk 1 - Starting to do work

5279 [9] info程序块1 - 结尾工程

5279 [9] INFO Program chunk 1 - Finishing work

5279 [9] info程序块2 - 开始做的工作。

5279 [9] INFO Program chunk 2 - Starting to do work

10292 [9] info程序块2 - 结尾工程

10292 [9] INFO Program chunk 2 - Finishing work

10292 [9] info程序块3 - 开始做的工作。

10292 [9] INFO Program chunk 3 - Starting to do work

15299 [9] info程序块3 - 结尾工程

15299 [9] INFO Program chunk 3 - Finishing work

不过,我无法弄清楚如何维护,使用'正常'的异步​​方法。

However, I can't figure out how to maintain that using 'normal' async methods.

例如,试图做到这一点:

For instance, trying to do this:

private static ILog s_logger = LogManager.GetLogger("Program");

static void Main(string[] args)
{
    BasicConfigurator.Configure();

    var task1 = DoSomeWork("chunk 1");
    var task2 = DoSomeWork("chunk 2");
    var task3 = DoSomeWork("chunk 3");

    Task.WaitAll(task1, task2, task3);
}

static async Task DoSomeWork(string chunkName)
{
    using (log4net.LogicalThreadContext.Stacks["NDC"].Push(chunkName))
    //using (log4net.ThreadContext.Stacks["NDC"].Push(chunkName))
    {
        s_logger.Info("Starting to do work");
        await Task.Delay(5000);
        s_logger.Info("Finishing work");
    }
}

显示他们都开始正常,但是当任务在不同的线程完成,堆栈丢失(我希望在log4net.LogicalThreadContext是TPL-'aware我猜的)。

Shows them all starting "normally", but when the task completes on a different thread, the stack is lost (I was hoping the log4net.LogicalThreadContext would be TPL-'aware' I guess).

234 [10] info程序块1 - 开始做的工作。

234 [10] INFO Program chunk 1 - Starting to do work

265 [10] info程序块2 - 开始做的工作。

265 [10] INFO Program chunk 2 - Starting to do work

265 [10] info程序块3 - 开始做的工作。

265 [10] INFO Program chunk 3 - Starting to do work

5280 [7] INFO计划(空) - 整理工作。

5280 [7] INFO Program (null) - Finishing work

5280 [12]信息计划(空) - 整理工作。

5280 [12] INFO Program (null) - Finishing work

5280 [12]信息计划(空) - 整理工作。

5280 [12] INFO Program (null) - Finishing work

添加一个新的TaskContext(或类似),以log4net的之外,有没有追踪这种活动的一种方式?

Outside of adding a new TaskContext (or the like) to log4net, is there a way of tracking this kind of activity?

我们的目标是真的这样做异步/的await语法糖 - 要么迫使一些线程关联的或做这样的事情保持周围由任务键入一个并发的字典是可能奏效的办法,但我试图保持作为关闭到code尽可能的同步版本。 :)

The goal is really to do so with the async/await syntax sugar - either forcing some kind of thread affinity or doing things like keeping a concurrent dictionary around keyed by task are likely workable options, but I'm trying to keep as close to the synchronous version of the code as possible. :)

推荐答案

有不适合异步逻辑调用上下文一个好故事现在。

There isn't a good story for async logical call contexts right now.

<击> CallContext中不能被用于此目的。逻辑 CallContext中不知道如何异步方法提前返回并在以后继续,这样就不会总是正确的工作code,使用简单的并行性,如 Task.WhenAll

CallContext can't be used for this. The logical CallContext doesn't understand how async methods return early and resume later, so it will not always work correctly for code that uses simple parallelism such as Task.WhenAll.

更新: CallContext中最后一次更新的.NET 4.5 RTW正确与工作异步方法。

Update: CallContext was updated in .NET 4.5 RTW to correctly work with async methods.

我看着log4net的; LogicalThreadContext 记录为使用 CallContext中,但有,使得它使用非逻辑上下文(固定在一个错误他们在SVN 2012年2月2日;当前版本1.2.11不包括更正)。即使它的固定,但是,它仍然无法与异步工作(因为逻辑 CallContext中不起作用与异步)。

I looked into log4net; LogicalThreadContext is documented as using CallContext, but there was a bug that made it use the non-logical contexts (fixed in their SVN on Feb 2, 2012; the current 1.2.11 release does not include that fix). Even when it's fixed, though, it'll still not work with async (because the logical CallContext doesn't work with async).

当我需要一个异步逻辑通话情况下,我让包含上下文数据,并保持所有的异步方法。这是的确实的不是一个理想的解决方案,但它是一个肮脏的黑客的作品。

When I need an async logical call context, I make a class that contains the context data and keep all of my async methods in a functional style as instance members of that class. This is certainly not an ideal solution, but it's a dirty hack that works.

在此期间,请给予好评的<一个href=\"http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2698599-add-an-async-compatible-logical-call-context-\">suggestion微软提供一些机制,这。

In the meantime, please upvote the suggestion that Microsoft provide some mechanism for this.

P.S。通过任务键控并发字典将无法工作,因为异步方法不一定是正在运行的任务(例如,在你的例如code,在使用语句, Task.CurrentId 因为没有任务实际上在该点执行)。

P.S. A concurrent dictionary keyed by Task won't work, because async methods are not necessarily running tasks (i.e., in your example code, at the using statement, Task.CurrentId would be null because there is no task actually executing at that point).

和线程关联都有它自己的问题了。实际上,你最终需要为每个独立的异步操作一个单独的线程。再见,可扩展性...

And thread affinity has its own problems, too. You actually end up needing a separate thread for each independent asynchronous operation. Bye-bye, scalability...

这篇关于如何使用异步管理一个NDC样log4net的堆栈/ await方法? (每个任务堆栈?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆