我在ASP.NET MVC 3应用中有一个搜索操作,它返回包含的建议以及带有给定关键字的标记:
[HttpPost]
public ActionResult Search(string query, int pg = 0)
{
var keywords = query.Split(new[] { ' ', ',', ';' },
StringSplitOptions.RemoveEmptyEntries);
var containing = (from s in _readonlySession.All<Suggestion>()
from k in keywords
where (s.Text.ToLower().Contains(k.ToLower()))
orderby s.Text
select s).Distinct();
var tagged = (from t in _readonlySession.All<Tag>()
from s in t.Suggestions
from k in keywords
where t.Text.ToLower().Contains(k.ToLower())
orderby s.Text
select s).Distinct();
var model = new SearchViewModel
{
Query = query,
Containing = containing.ToList(),
Tagged = tagged.ToList()
};
return View(model);
}
我认为containing
和tagged
查询可以完美并行运行。
同时触发这两个查询的最佳方法是什么,等待结果,并且仅在两个查询完成时返回?
答案 0 :(得分:8)
任务Parallels库是您的最佳选择。通过Google获取大量信息,但下面是您的实施可能的样子。
[HttpPost]
public ActionResult Search(string query, int pg = 0)
{
var keywords = query.Split(new[] { ' ', ',', ';' },
StringSplitOptions.RemoveEmptyEntries);
IEnumerable containing=null;
Task t1 = Task.Factory.StartNew(() =>
{
containing = (from s in _readonlySession.All<Suggestion>()
from k in keywords
where (s.Text.ToLower().Contains(k.ToLower()))
orderby s.Text
select s).Distinct().ToList();
});
IEnumerable tagged=null;
Task t2 = Task.Factory.StartNew(() =>
{
var tagged = (from t in _readonlySession.All<Tag>()
from s in t.Suggestions
from k in keywords
where t.Text.ToLower().Contains(k.ToLower())
orderby s.Text
select s).Distinct().ToList();
});
t1.Wait();
t2.Wait();
var model = new SearchViewModel
{
Query = query,
Containing = containing.ToList(),
Tagged = tagged.ToList()
};
return View(model);
}
请记住,如果您的应用程序收到大量请求,那么不异步执行查询可能会更好 - 消耗2个额外的线程来为一个请求提供服务会使资源远离其他传入请求。如果您拥有大量流量,或者您的硬件不足,这只会是一个问题。
答案 1 :(得分:3)
您希望在网页中使用TPL时要小心,因为TPL将利用本来用于处理其他HTTP请求的线程。从本质上讲,您可以在单个请求上降低响应延迟,降低请求的总体吞吐量。
有关权衡的更多解释,请参阅以下文章:
http://blogs.msdn.com/b/pfxteam/archive/2010/02/08/9960003.aspx
答案 2 :(得分:2)
这可能是async controller的良好候选人。关于异步控制器的重要一点是,如果您希望在这种情况下获得净性能增益,则需要修改存储库层并提供两种方法的异步版本,这两种方法在与远程系统(如远程系统)通信时理想地使用I / O完成端口数据库。
public class SearchController: AsyncController
{
public void SearchAsync(string query, int pg = 0)
{
// TODO: Write a custom model binder to do this job
// and have your controller action directly take an
// IEnumerable<string> argument.
var keywords = query.Split(new[] { ' ', ',', ';' },
StringSplitOptions.RemoveEmptyEntries);
AsyncManager.OutstandingOperations.Increment();
AsyncManager.OutstandingOperations.Increment();
_readonlySession.GetContainingCompleted += (sender, e) =>
{
AsyncManager.Parameters["containing"] = e.Value;
AsyncManager.OutstandingOperations.Decrement();
};
_readonlySession.GetTaggedCompleted += (sender, e) =>
{
AsyncManager.Parameters["tagged"] = e.Value;
AsyncManager.OutstandingOperations.Decrement();
};
_readonlySession.GetContainingAsync(keywords);
_readonlySession.GetTaggedAsync(keywords);
AsyncManager.Parameters["query"] = query;
}
public ActionResult SearchCompleted(string query, IEnumerable<Suggestion> containing, IEnumerable<Tag> tagged)
{
var model = new SearchViewModel
{
Query = query,
Containing = containing.ToList(),
Tagged = tagged.ToList()
};
return View(model);
}
}