繁体   English   中英

如何初始化可选任务和任务<T>使用 C#?

[英]How to initilize an optional Task and Task<T> using C#?

如何选择创建多个任务并使用await Task.WhenAll(a,b,c);执行它们await Task.WhenAll(a,b,c);

我有以下课程

public class TaskProcessor
{
    private ProcessResult Result;

    public TaskProcessor(ProcessResult result)
    {
        Result = result ?? throw new ArgumentNullException(nameof(result));
    }

    public async Task<ProcessResult> Process(TaskOption option)
    {
        // First optional task
        Task<int?> typeFetcher = Task.FromResult<int?>(null);
        if (option is IProcessType t)
        {
            typeFetcher = t.GetAsync();
        }

        // Second optional task
        Task<int?> subtypeFetcher = Task.FromResult<int?>(null);
        if (option is IProcessSubtype st)
        {
            subtypeFetcher = st.GetAsync();
        }

        // Third optional task
        Task mainContent = Task.CompletedTask;

        if(Result.Content != null) 
        {
            mainContent = SetMainContentAsync(Result.Content);
        }

        await Task.WhenAll(typeFetcher, subtypeFetcher, mainContent);

        Result.TypeId = typeFetcher.Result,
        Result.SubtypeId = subtypeFetcher.Result;

        return result;
    }
}

我想将任务初始化为不执行任何操作的默认值。 正如你在上面的代码中看到的, typeFetcher任务是使用Task.FromResult<int?>(null);初始化的Task.FromResult<int?>(null); 并且当给定的TaskOption实现IProcessType接口时,使用自定义任务覆盖该任务。 同样的场景也适用于subtypeFetcher任务。

对于mainContent任务,我使用Task.CompletedTask初始化它,当Result.Content不为空时,我将mainContent设置为SetMainContentAsync(Result.Content) 最后,我使用await Task.WhenAll(typeFetcher, subtypeFetcher, mainContent)等待所有任务。

ASP.NET Core 性能最佳实践声明如下

不要:通过调用Task.WaitTask.Result阻止异步执行。

因为我使用的是Task.FromResult<int?>(null); 初始化任务,我觉得我违反了最佳实践。 我想学习初始化可选任务的正确方法。

问题初始化返回类型的可选任务的正确方法是什么? 另外,初始化一个不向Task.CompletedTask返回任何内容的任务是可以接受的还是有更正确的方法?

你在做什么很好。 Task.FromResult不是Task.Result ,两者完全无关。

Task.Result是一个实例属性,它阻塞当前线程直到任务完成,并返回任务的结果。

Task.FromResult是一个静态方法,它返回一个微不足道的、已经完成的任务。

首先要做的事情是:以您的方式使用.Result是“确定的”,因为您已经通过使用await Task.WhenAll确保它已完成。 您的代码不会坐在.Result等待结果并阻塞线程。 但由于处理异常的方式,我在引号中说“ok”。 当您使用.Result ,异常总是放在AggregateException ,您必须查看内部才能找到真正的异常。

但是,您仍然可以对已完成的任务使用await ,并且会按照您的预期抛出异常:

Result.TypeId = await typeFetcher;

至于问题的其余部分:我发现等待多个可选任务的最佳方法是使用List<Task>并只添加所需的任务。

var taskList = new List<Task>();

但是,由于您需要使用任务的返回值,因此这很复杂。 有几种方法可以解决这个问题。 您可以使用等待的列表,但也可以像以前一样保留对每个任务本身的引用。 Task初始化为null并且仅在它不是null时才设置该值。 例如:

var taskList = new List<Task>();

Task<int?> typeFetcher = null;
if (option is IProcessType t)
{
    typeFetcher = t.GetAsync();
    taskList.Add(typeFetcher);
}

...

await Task.WhenAll(taskList);

if (typeFetcher != null)
{
    Result.TypeId = await typeFetcher;
}

...

但是你对同一件事保留两个引用是......我不知道。 好像还可以做得更好。

另一种选择是使用设置值的本地函数并将其添加到您的任务列表中。 这样,您不必在等待后设置值。

public async Task<ProcessResult> Process(TaskOption option)
{
    var taskList = new List<Task>();

    // First optional task
    if (option is IProcessType t)
    {
        // Declare a local function that sets the value
        async Task TypeFetcher()
        {
            Result.TypeId = await t.GetAsync();
        }

        // Call it and add the resulting Task to the list
        taskList.Add(TypeFetcher());
    }

    // Second optional task
    Task<int?> subtypeFetcher = Task.FromResult<int?>(null);
    if (option is IProcessSubtype st)
    {
        async Task SubtypeFetcher()
        {
            Result.SubtypeId = await st.GetAsync();
        }
        taskList.Add(SubtypeFetcher());
    }

    // Third optional task
    if(Result.Content != null) 
    {
        //don't need a local function here since there's no return value
        taskList.Add(SetMainContentAsync(Result.Content));
    }

    await Task.WhenAll(taskList);

    //I assume you actually declared and set result somewhere
    return result;
}

我并不是说这比保留对每个Task两个引用更有效。 只做你觉得最不容易混淆的事情。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM