这是我的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
?
答案 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
进行的await
是Task.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); } }
);