使用Task.Run的后台线程

时间:2015-06-08 23:11:58

标签: c# .net multithreading task-parallel-library task

在为Oracle数据库查询和Active Directory查询生成两个单独的任务然后等待这两个任务时,您是否看到任何陷阱或问题。

下面是一个非常基本的剥离示例。基本上,我们有一个员工对象,它是从AD和Oracle DB的信息中创建的。 (顺序调用)

var partialEmployeeA=ActiveDirectoryLookup(employeeID);

var partialEmployeeB=OracleDBLookup(employeeID);

var finalEmployee=Merge(partialEmployeeA,partialEmployeeB);

此时,Employee对象已创建并从两个查询拼凑在一起,可以使用。这没有问题,但如果这些调用中的每一个都是它自己的任务,你会从扩展视角看到任何问题吗? (不包括任何其他明显的代码问题)

Employee partialEmployeeA;
Employee partialEmployeeB;

var t1 = Task.Run(() => {
   partialEmployeeA=ActiveDirectoryLookup(employeeID);
});

var t2 = Task.Run(() => {
   partialEmployeeB=OracleDBLookup(employeeID);
});,

Task.WaitAll(t1, t2);
var finalEmployee=Merge(partialEmployeeA,partialEmployeeB);

我用秒表类进行了一些测试,每次Task版本恢复得更快(平均值:100-120ms vs 200-250ms)并没有问题,但不确定这是如何缩放的多核系统。我没有对TPL做过很多,但对这种方法很好奇。

1 个答案:

答案 0 :(得分:6)

我没有看到任何问题,这些是不同的服务,可能不会分享任何州。

但是,您应该意识到,在这两种情况下,您将占用3个在整个异步(I / O)操作中阻塞的线程

通过利用多个线程并行执行这些操作会更快。但它实际上更具可扩展性

要做到这一点"对"在不阻塞线程和耗尽资源的情况下,您需要将这些操作视为真正的异步,而不仅仅是在后台线程上:

var partialEmployeeATask = ActiveDirectoryLookupAsync(employeeID);
var partialEmployeeBTask = OracleDBLookupAsync(employeeID);

await Task.WhenAll(partialEmployeeATask, partialEmployeeBTask)
var finalEmployee = Merge(await partialEmployeeATask, await partialEmployeeBTask);

这需要更改API以支持某种形式的异步请求。如果API不在您的控制之下,则可能是一个问题。如果不能这样做,至少只使用Task.Run一次并使用" main"线程到另一部分。