从在单独线程上运行的方法返回列表

时间:2018-07-26 11:00:35

标签: c# asp.net-core asp.net-core-mvc asp.net-core-2.0

这是我的ActionMethod

public IActionResult GetMember(string BCode)
{
    Info model = new Info();

    try
    {
        model.BList = GetBList();

        if (BCode != null)
        {
            model.MemberList = GetMemberList(BCode);
        }
    }
    catch (Exception ex)
    {
        TempData["Msg"] = ex.Message;
    }
    finally
    {
    }

    return View("Index", model);
}

public List<PendingListBranchWise> GetBList()
        {
            using (IDbConnection db = new SqlConnection(configuration.GetConnectionString("constr")))
            {
                return (List<PendingListBranchWise>)db.Query<PendingListBranchWise>("sp_GetClientDetails", new { value = "GetBranchList" }, commandType: CommandType.StoredProcedure);
            }
        }

public List<pendingListMemberWise> GetMemberList(string BCode)
        {
            using (IDbConnection db = new SqlConnection(configuration.GetConnectionString("constr")))
            {
                return (List<pendingListMemberWise>)db.Query<pendingListMemberWise>("sp_GetClientDetails", new { value = BCode }, commandType: CommandType.StoredProcedure);
            }
        }

这是一个简单的代码,运行两个返回List<SelectListItem>的方法

model.BList = GetBList();
model.MemberList = GetMemberList(BCode);

我不想以顺序的方式运行它们,因为它们彼此独立,所以对我来说可用的选择是使用线程:

Thread t = new Thread(new ThreadStart(GetBList));
t.Start();
t.Join();

如果GetBranchList()没有返回类型,但我需要返回List<SelectListItem>,则可以使用。

显示编译错误

  

List<PendingListBranchWise> GetBranchList()'的返回类型错误

如何在单独的线程上运行时从此方法返回List

2 个答案:

答案 0 :(得分:2)

因此,这是TPL(任务并行库)可以用作的一个好例子。实际上很少要在Task上处理原始线程的情况很少。 您的代码最简单的重写是:

public async Task<IActionResult> GetMemberList(string BCode)
{
    Info model = new Info();

    try
    {
        Task<List<B>> getBListTask = Task.Run(() => GetBList());
        Task<List<Member>> memberListTask = Task.FromResult(null);
        if (BCode != null)
        {
            memberListTask = Task.Run(() => GetMemberList(BCode));
        }

        await Task.WhenAll(getBListTask, memberListTask);

        model.BList = getBListTask.Result;
        if(BCode != null)
        {
            model.MemberList = memberListTask.Result;
        }
    }
    catch (Exception ex)
    {
        TempData["Msg"] = ex.Message;
    }
    finally
    {
    }

    return View("Index", model);
}

现在,如果不了解问题,重写问题将毫无用处。 顾名思义,Task可以看作是一项需要完成的任务。 这可能是一些不返回任何内容的工作(Task,也可能是一个返回值(Task<TValue>)的工作。 TPL的作用是让您抽象化Thread附带的许多并发和同步问题。请注意,它并没有结束于线程,但是有很多合格的人谈论这个话题。

我写的基本上是告诉TPL启动两个任务。一个用于GetBList(),另一个用于GetMemberList()。 TPL将决定如何以及何时运行这些任务。当我决定要这些值时(在这种情况下,在我分配模型值之前),我await执行任务。 await基本上告诉编译器生成一些中间代码,这些中间代码说:“直到提供的任务完成运行后,我才能继续执行,因此请唤醒它”。在这种情况下,要Task进行的awaitTask.WhenAll( getBListTask, memberListTask)

然后我可以从每个Task对象中获得单独的结果。

我已经非常简化了这里的操作,但这应该可以帮助您入门。
我建议阅读Jon Skeet的以下答案:
Task vs Thread differences
该线程中的其他答案也很好。

编辑 我已经看到您正在使用Dapper。请注意,许多Dapper方法具有*Async变体。还记得我说任务是工作单位吗?任何返回Task的方法都说这是一个工作单元。这并不明确表示这是CPU约束的工作(例如启动线程并运行计算)。这可能是IO绑定的工作,就像打远程DB。在这种情况下,他们可能通过回调和中断来实现Task。同样,在使用任务时,您不必在大多数时间里都太担心。我将对async await模式进行一些阅读,看看是否可以使用Dapper方法的Async变体。一种方法是将GetBList定义为:

public async Task<List<PendingListBranchWise>> GetBListAsync()
    {
        using (IDbConnection db = new SqlConnection(configuration.GetConnectionString("constr")))
        {
            return await (List<PendingListBranchWise>)db.QueryAsync<PendingListBranchWise>("sp_GetClientDetails", new { value = "GetBranchList" }, commandType: CommandType.StoredProcedure).ConfigureAwait(false);
        }
    }

您可以在这里看到,现在GetBListAsync返回一个Task,现在您可以将Task.Run() => GetBlist());替换为一个简单的GetBListAsync()。本质上,我们已经将Task的委托下推到GetBListAsync,并通过它下到QueryAsync

答案 1 :(得分:1)

model.BList = GetBList();

if (BCode != null)
{
    model.MemberList = GetMemberList(BCode);
}

可以像这样并行进行:

Parallel.Invoke(
    () => { model.BList = GetBList(); },
    () => { if (BCode != null) { model.MemberList = GetMemberList(BCode); } }
);