后台线程使用Task.Run

本文关键字:Task Run 线程 后台 | 更新日期: 2023-09-27 17:54:46

当为Oracle数据库查询和Active Directory查询生成两个单独的任务,然后等待两个任务时,您是否发现任何陷阱或问题?

下面是一个非常简单的例子。从本质上讲,我们有一个雇员对象,从AD和Oracle数据库的信息块中创建。(称为顺序)

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做得不多,但对这种方法很好奇。

后台线程使用Task.Run

我不认为这有什么问题,这些不同的服务有不同的请求,可能不会共享任何状态。

然而,您应该意识到,在这两种情况下,您都占用了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只一次,并使用"主"线程到另一部分。