Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 由多个线程使用的Post Sharp属性中的唯一记录器_C#_Multithreading_Task Parallel Library_Postsharp - Fatal编程技术网

C# 由多个线程使用的Post Sharp属性中的唯一记录器

C# 由多个线程使用的Post Sharp属性中的唯一记录器,c#,multithreading,task-parallel-library,postsharp,C#,Multithreading,Task Parallel Library,Postsharp,我已经实现了如下所示的Postsharp属性,下面是使用细节: 可以使用static Func GetLogger或static ThreadLocal TestLogger,它们是通过HelloTask方法从主程序设置的 目标是为调用方法DoTask 我对设置static Func或static ThreadLocal相当谨慎,并认为这会由于多个线程而导致问题(争用条件或损坏),但从Main方法中可以看出,即使调用了100个任务,它也能很好地工作,这是正确的方法吗?哪种方法更好,我想Thr

我已经实现了如下所示的
Postsharp
属性,下面是使用细节:

  • 可以使用
    static Func GetLogger
    static ThreadLocal TestLogger
    ,它们是通过
    HelloTask
    方法从主程序设置的
  • 目标是为调用方法
    DoTask
我对设置
static Func
static ThreadLocal
相当谨慎,并认为这会由于多个线程而导致问题(争用条件或损坏),但从Main方法中可以看出,即使调用了100个任务,它也能很好地工作,这是正确的方法吗?哪种方法更好,我想ThreadLocal会更好

有没有更好的方法达到同样的效果?

    [Serializable]
    public class LogExecutionTimeAttribute : OnMethodBoundaryAspect
    {

    [NonSerialized]
    public static Func<ILog> GetLogger;

    [NonSerialized]
    public static ThreadLocal<ILog> TestLogger;

    public LogExecutionTimeAttribute()
    {
        // Setting AspectPriority explicity avoids undeterministic behaviour 
        // when multiple aspects are applied, and avoids warning messages
        this.AspectPriority = 1;
    }       

    public override void OnEntry(MethodExecutionArgs args)
    {
        args.MethodExecutionTag = Stopwatch.StartNew();
        base.OnEntry(args);
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        Stopwatch sw = (Stopwatch)args.MethodExecutionTag;
        sw.Stop();
        var logger =
     #if Func
           GetLogger();
     #else
        TestLogger.Value;
     #endif 

        logger.DebugFormat(
            "{0}.{1} for Id={2} executed in {3} seconds.", 
            this.className, 
            this.methodName, 
            args.Arguments[0],
            sw.ElapsedMilliseconds / 1000.0);
        base.OnExit(args);
      }
     }
[可序列化]
公共类LogExecutionTimeAttribute:OnMethodBoundaryAspect
{
[非串行化]
公共静态函数GetLogger;
[非串行化]
公共静态线程本地测试记录器;
公共日志ExecutionTimeAttribute()
{
//明确设置AspectPriority可避免不确定行为
//当应用多个方面时,避免出现警告消息
this.AspectPriority=1;
}       
public override void OnEntry(MethodExecutionArgs args)
{
args.MethodExecutionTag=Stopwatch.StartNew();
base.OnEntry(args);
}
公共重写void OnExit(MethodExecutionArgs args)
{
秒表sw=(秒表)args.MethodExecutionTag;
sw.Stop();
var记录器=
#如果Func
GetLogger();
#否则
TestLogger.Value;
#恩迪夫
logger.DebugFormat(
“{0}.{1}for Id={2}在{3}秒内执行。”,
这个.className,
这个.methodName,
参数[0],
sw.ElapsedMills/1000.0);
base.OnExit(args);
}
}
用法如下:

 class Program
    {

   static void Main(string[] args)
        {
            var taskList = new List<Task>();

            for (var counter = 0; counter < 100; counter++)
            {
                var localCounter = counter;

                taskList.Add(Task.Factory.StartNew(() => HelloTask(localCounter + 1), TaskCreationOptions.LongRunning));
            }

            Task.WaitAll(taskList.ToArray());
        }

        [LogExecutionTime]
        private static void DoTask(int id)
        {
 #if Func
            LogExecutionTimeAttribute.GetLogger().Info(id);
#else
                LogExecutionTimeAttribute.TestLogger.Value.Info(id);
#endif
        }


        private static void HelloTask(int id)
        {
            var log  = new LogFileLogger(id.ToString()).LogInstance;

            #if Func
                LogExecutionTimeAttribute.GetLogger = () => log;
            #else
                LogExecutionTimeAttribute.TestLogger = new ThreadLocal<ILog>(() => log);
            #endif

            var sw = Stopwatch.StartNew();

            for (var i = 0; i < 50; i++)
            {
                DoTask(i);
            }

            sw.Stop();

        #if Func
            LogExecutionTimeAttribute.GetLogger().Info("Time :: " + sw.ElapsedMilliseconds);
        #else
            LogExecutionTimeAttribute.TestLogger.Value.Info("Time :: " + sw.ElapsedMilliseconds);
        #endif

        }    

    }
类程序
{
静态void Main(字符串[]参数)
{
var taskList=新列表();
用于(变量计数器=0;计数器<100;计数器++)
{
var localCounter=计数器;
taskList.Add(Task.Factory.StartNew(()=>HelloTask(localCounter+1),TaskCreationOptions.LongRunning));
}
Task.WaitAll(taskList.ToArray());
}
[日志执行时间]
私有静态void点任务(int-id)
{
#如果Func
LogExecutionTimeAttribute.GetLogger().Info(id);
#否则
LogExecutionTimeAttribute.TestLogger.Value.Info(id);
#恩迪夫
}
私有静态void HelloTask(int-id)
{
var log=new LogFileLogger(id.ToString()).LogInstance;
#如果Func
LogExecutionTimeAttribute.GetLogger=()=>log;
#否则
LogExecutionTimeAttribute.TestLogger=新线程本地(()=>log);
#恩迪夫
var sw=Stopwatch.StartNew();
对于(变量i=0;i<50;i++)
{
DoTask(i);
}
sw.Stop();
#如果Func
LogExecutionTimeAttribute.GetLogger().Info(“时间::”+sw.ElapsedMilliseconds);
#否则
LogExecutionTimeAttribute.TestLogger.Value.Info(“时间::”+sw.ElapsedMilliseconds);
#恩迪夫
}    
}

如响应中所述:当每个线程有不同的记录器实例时,应将其存储在线程静态或线程本地字段中,以避免并发问题

从设计的角度来看,最好使方面独立于您创建记录器实例的方式。因此,例如,在应用程序启动时只分配一次静态的
GetLogger
,并将其留给方面消费者来决定是应该为每个线程、每个实例还是每个应用程序创建记录器

[Serializable]
public class LogExecutionTimeAttribute : OnMethodBoundaryAspect
{
    public static Func<ILog> GetLogger;
    // ...
}

public static class LoggerFactory
{
    [ThreadStatic]
    public static ILog Logger;

    public static ILog GetLogger()
    {
        return Logger;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Configure factory only once.
        LogExecutionTimeAttribute.GetLogger = LoggerFactory.GetLogger;
        // ...
    }

    private static void HelloTask(int id)
    {
        var log  = new LogFileLogger(id.ToString()).LogInstance;
        LoggerFactory.Logger = log;
        // ...
     }
}
[可序列化]
公共类LogExecutionTimeAttribute:OnMethodBoundaryAspect
{
公共静态函数GetLogger;
// ...
}
公共静态类LoggerFactory
{
[线程静态]
公共静态ILog记录器;
公共静态iloggetlogger()
{
返回记录器;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
//只配置工厂一次。
LogExecutionTimeAttribute.GetLogger=LoggerFactory.GetLogger;
// ...
}
私有静态void HelloTask(int-id)
{
var log=new LogFileLogger(id.ToString()).LogInstance;
LoggerFactory.Logger=log;
// ...
}
}

您可以从本文档页面的方面了解更多关于使用依赖项的信息:

谢谢,正如我所理解的,使用
ThreadLocal
的选项将是一个很好的选择,这将按预期完成工作,顺便说一句,以防代码审查问题对其相似性感兴趣,这是因为我们是同一个团队的一员,正在寻找同一问题的解决方案,只是我认为
ThreadLocal
是建议的
ThreadStatic
的更新方法