订购异步方法调用

时间:2011-05-04 21:43:12

标签: c# asp.net threadpool

我正在开发一个类库,它根据Web配置文件中定义的策略,在几种类型的数据源(文件,xml,数据库)中记录Web应用程序的审核详细信息。

我的审核日志方法有一个类似于此的签名: public static void LogInfo(用户用户,模块模块,List lst);

Web应用程序使用此方法记录重要的详细信息,如警告,错误甚至异常详细信息。

由于在单个工作流程中,有超过700多个调用这些方法,我想让它们异步。我使用了来自 ThreadPool 类的简单方法,名为 QueueUserWorkItem

ThreadPool.QueueUserWorkItem(o => LogInfo(User user, Module module, List<Object> lst) );

但这并不能确保工作项排队的顺序。即使记录了我的所有信息,但整个订单都搞砸了。在我的文本文件中,我的日志不是按照调用它们的顺序。

有没有办法可以控制使用QueueUserWorkItem调用的线程的顺序?

2 个答案:

答案 0 :(得分:3)

我不认为您可以在使用QueueUserWorkItem时指定排序。

要并行运行日志记录(在某些后台线程上),您可以使用ConcurrentQueue<T>。这是一个可以从多个线程访问的线程安全集合。您可以创建一个工作项(或一个线程),从集合中读取元素并将它们写入文件。您的主应用程序会将项目添加到集合中。您从单个线程向集合中添加项目的事实应该保证它们将以正确的顺序读取。

为简单起见,您可以在队列中存储Action值:

ConcurrentQueue<Action> logOperations = new ConcurrentQueue<Action>();

// To add logging operation from main thread:
logOperations.Add(() => LogInfo(user, module, lst));

后台任务可以从队列中取出Action并运行它们:

// Start this when you create the `logOperations` collection
ThreadPool.QueueUserWorkItem(o => {
    Action op;
    // Repeatedly take log operations & run them
    while (logOperations.TryDequeue(out op)) op();
});

如果您需要停止后台处理器(将数据写入日志),您可以创建CancellationTokenSource并在取消令牌时结束while循环(通过主线程) )。使用IsCancellationRequested属性(see MSDN

检查此问题

答案 1 :(得分:0)

解决此问题的一种方法是将您的数据放入队列,然后从该队列中挑选一个任务并按顺序编写它们。如果您使用的是.net 4.0您可以使用ConcurrentQueue,这是线程安全的,否则具有正确锁定的简单队列也可以。

消耗队列的线程然后可以定期检查队列中的任何元素,并且对于它们中的每一个元素,它都可以记录。这样,冗长的操作(日志记录)可以在它自己的线程中,而在主线程中你只需添加。