gpt4 book ai didi

linq - 如何在不运行它们的情况下合并两个 Linq IEnumerable 查询?

转载 作者:行者123 更新时间:2023-12-04 21:20:03 27 4
gpt4 key购买 nike

我如何合并 List<T>用于以后执行的基于 TPL 的任务?

 public async IEnumerable<Task<string>> CreateTasks(){ /* stuff*/ }

我的假设是 .Concat() ...
     void MainTestApp()  // Full sample available upon request.
{
List<string> nothingList = new List<string>();
nothingList.Add("whatever");
cts = new CancellationTokenSource();

delayedExecution =
from str in nothingList
select AccessTheWebAsync("", cts.Token);
delayedExecution2 =
from str in nothingList
select AccessTheWebAsync("1", cts.Token);

delayedExecution = delayedExecution.Concat(delayedExecution2);
}


/// SNIP

async Task AccessTheWebAsync(string nothing, CancellationToken ct)
{
// return a Task
}

我想确保这不会产生任何任务或评估任何东西。事实上,我想我在问“什么逻辑上执行 IQueryable 到返回数据的东西”?

背景

由于我正在执行递归并且我不想在正确的时间执行此操作,如果多次调用,合并结果的正确方法是什么?

如果重要,我正在考虑运行此命令来启动所有任务 var AllRunningDataTasks = results.ToList();后面跟着这个代码:
while (AllRunningDataTasks.Count > 0)
{
// Identify the first task that completes.
Task<TableResult> firstFinishedTask = await Task.WhenAny(AllRunningDataTasks);

// ***Remove the selected task from the list so that you don't
// process it more than once.
AllRunningDataTasks.Remove(firstFinishedTask);

// TODO: Await the completed task.
var taskOfTableResult = await firstFinishedTask;

// Todo: (doen't work)
TrustState thisState = (TrustState)firstFinishedTask.AsyncState;

// TODO: Update the concurrent dictionary with data
// thisState.QueryStartPoint + thisState.ThingToSearchFor

Interlocked.Decrement(ref thisState.RunningDirectQueries);
Interlocked.Increment(ref thisState.CompletedDirectQueries);

if (thisState.RunningDirectQueries == 0)
{
thisState.TimeCompleted = DateTime.UtcNow;
}
}

最佳答案

要回答特定问题“什么逻辑上执行 IQueryable 到返回数据的东西”?这将是任何强制产生至少一个值或强制发现值是否可用的任何东西。

例如,ToList , ToArray , First , Single , SingleOrDefault , 和 Count将所有的力量评估。 (尽管 First 不会评估整个集合 - 它会检索第一个项目然后停止。)这些都必须至少开始检索值,因为它们中的任何一个都无法在不这样做的情况下返回它们返回的内容.在ToList的情况下和 ToArray ,这些返回完全填充的非惰性集合,这就是为什么它们必须评估所有内容。返回单个项的方法至少需要请求第一项,以及 Single然后,如果继续评估,将继续检查是否没有其他结果(如果结果更多,则抛出异常)。

使用 foreach迭代查询也将强制评估。 (同样,出于同样的原因:您要求它从集合中获取实际值,因此它必须提供它们。)
Concat不会立即评估,因为它不需要 - 只有当您向串联序列询问一个值时,它才需要向其输入询问值。

顺便说一句,尽管您询问了 IQueryable您没有在此处的示例中使用它。这可能很重要,因为与您实际获得的 LINQ to Objects 实现(您通过普通 IEnumerable<T> 获得)相比,它的工作方式存在一些差异。我认为这在这个例子中没有什么不同,但它让我想知道你的原始代码和你在这里发布的用于说明的版本之间是否有什么变化?这很重要,因为不同的 LINQ 提供程序可以以不同的方式做事。 IEnumerable<T> flavor Concat肯定使用延迟评估,虽然我希望这对于大多数其他 LINQ 实现是正确的,但它并不是绝对给定的。

如果你需要多次使用结果,并且你想确保你只对它们进行一次评估,但在你真正需要它们之前不评估它们,那么通常的方法是调用 ToList在您肯定需要评估的地方,然后保留结果 List<T>所以你可以再次使用它。一旦您获得了 List<T> 中的数据(或数组)形式,您可以根据需要多次使用该列表。

顺便说一下,你的第一个问题有一个问题:

“如何合并基于 TPL 的任务列表以供以后执行?”

通常,如果您已经有一个 TPL 任务,那么您无法阻止它执行。 (有一个异常(exception)。如果你直接构造一个 Task 而不是使用一种更正常的创建方式,它实际上不会运行,直到你告诉它。但一般来说,返回任务的 API 会返回活的,即,当您接触它们时,它们很可能已经在运行,甚至已经完成。)

您的示例中的“稍后执行”来自这样一个事实,即您实际上根本没有任务列表可以开始。 (如果您确实有 List<T> 个任务,“稍后执行”将不是一个选项。)您拥有的是几个可枚举,如果您要评估它们,将创建任务。创建任务的行为与在返回任务的任何 TAP 风格的 API 中启动它的行为是不可分割的。

根据您所写的其余内容,我认为您真正要问的是:

“如何将多个 IEnumerable<Task<T>> 对象合并为单个 IEnumerable<Task<T>>,从而推迟对基础枚举的评估,直到对组合的枚举本身进行评估?”
Concat应该为此工作。

关于linq - 如何在不运行它们的情况下合并两个 Linq IEnumerable<T> 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13663470/

27 4 0