将 MVC 迷你分析器计时纳入异步任务
我在页面内有一个长时间运行的 SQL 查询,我通过使用异步任务加速了该查询:(
using System.Threading.Tasks;
...
var asyncTask = new Task<ResultClass>(
() =>
{
using (var stepAsync = MiniProfiler.Current.Step("Async!"))
{
// exec long running SQL
}
});
asyncTask.Start();
// do lots of other slow stuff
ResultClass result;
using (var stepWait = MiniProfiler.Current.Step("Wait for Async"))
{
result = asyncTask.Result;
}
请注意,一旦 C# 5 推出 async
和 ,此语法将会好得多等待
)
当使用MVC迷你分析器时,我得到“等待异步”的时间,但我无法得到“异步!”的时间。步。
有什么方法可以将这些结果(也许只是 SQL 计时)放入已完成页面的跟踪中?
更新
我找到了一种让探查器进入异步方法的方法:
var asyncTask = new Task<ResultClass>(
profiler =>
{
using (var step = (profiler as MiniProfiler).Step("Async!"))
{
// exec long running SQL
}
}, MiniProfiler.Current);
这几乎有效,因为“异步!”步骤出现(有点随机,取决于执行,有时显示为负数),但并不是我真正想要的。 SQL 计时和语句仍然丢失,在这种情况下它们是最有价值的信息。
理想情况下,我希望“等待异步”步骤链接到计时(而不是开始步骤)。是否有某种方法可以将 stepWait
链接到结果的 SQL 探查器时间?
有什么想法吗?
I have a long running SQL query inside a page that I've sped up by using an async task:
using System.Threading.Tasks;
...
var asyncTask = new Task<ResultClass>(
() =>
{
using (var stepAsync = MiniProfiler.Current.Step("Async!"))
{
// exec long running SQL
}
});
asyncTask.Start();
// do lots of other slow stuff
ResultClass result;
using (var stepWait = MiniProfiler.Current.Step("Wait for Async"))
{
result = asyncTask.Result;
}
(Note that this syntax will be a lot nicer once C# 5 comes out with async
and await
)
When using MVC mini profiler I get the timing for "Wait for Async", but I can't get the timing for the "Async!" step.
Is there any way to get those results (maybe just the SQL timings) into the trace for the completed page?
Update
I've found a way to get the profiler steps into the async method:
var asyncTask = new Task<ResultClass>(
profiler =>
{
using (var step = (profiler as MiniProfiler).Step("Async!"))
{
// exec long running SQL
}
}, MiniProfiler.Current);
That almost works, in that the "Async!" step appears (somewhat randomly, depending on the execution, and with some times appearing as negative) but isn't really what I want. The SQL timings and statements are still lost, and in this case they're the most valuable information.
Ideally I'd like the "Wait for Async" step to be linked to the timings (rather than the start step). Is there some way that stepWait
could be linked to the SQL profiler times for the result?
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我找到了一种方法来做到这一点,只需保持主页面步骤的 SQL 计时仍然正确:
这会导致在 SQL 完成时将长时间运行的查询的 SQL 计时与当前步骤相关联。通常,这是等待异步结果的步骤,但如果 SQL 在我必须等待此结果之前完成,则这将是更早的步骤。
我已将其包装在一个简洁风格的
QueryAsync
扩展方法中(始终缓冲且不支持事务),尽管它可以做很多整理工作。当我有更多时间时,我会考虑添加ProfiledTask
或类似的内容,以允许从已完成的任务复制分析结果。更新 1(适用于 1.9)
根据 Sam 的评论(见下文),他说得很对:
AddSqlTiming
不是线程安全的。因此,为了解决这个问题,我已将其移至同步延续:这适用于 MvcMiniProfiler 1.9,但不适用于 MiniProfiler 2...
更新 2:MiniProfiler >=2
EF 内容版本 2 中添加的内容破坏了上面的 hack(它添加了一个仅限内部的
IsActive
标志),这意味着我需要一种新方法:一个新的实现用于异步任务的 BaseProfilerProvider :因此,要使用此提供程序,我只需在启动任务时启动它,并同步连接延续(如前所述):
现在 SQL 计时与以下步骤一致 :启动异步操作。 “% in sql” 超过了 100%,额外的 82.4% 是通过并行执行 SQL 节省的时间。
理想情况下,我会在等待步骤而不是初始化步骤上进行长时间运行的 SQL 查询,但我看不到一种方法可以在不更改调用方法的返回类型以显式传递计时的情况下执行此操作(这将使分析器更加引人注目)。
I've found a way to do this, by only keeping the SQL timings the main page steps still add up right:
This results in the SQL timings for the long running query being associated with the current step when the SQL completes. Typically this is the step waiting for the async result, but will be an earlier step if the SQL completes before I have to wait for this.
I've wrapped this in a dapper-style
QueryAsync<T>
extension method (always buffered and not supporting transactions) though it could do with a lot of tidy up. When I have more time I'll look into adding aProfiledTask<T>
or similar that allows the profiled results to be copied from the completed task.Update 1 (works in 1.9)
Following Sam's comment (see below) he's quite right:
AddSqlTiming
is not thread safe. So to get around that I've moved that to a synchronous continuation:This works in MvcMiniProfiler 1.9, but doesn't work in MiniProfiler 2...
Update 2: MiniProfiler >=2
The EF stuff added in version 2 breaks my hack above (it adds an internal-only
IsActive
flag), meaning that I needed a new approach: a new implementation ofBaseProfilerProvider
for async tasks:So then to use this provider I just need to start it when starting the task, and hook up the continuation synchronously (as before):
Now the SQL timings appear consistently against the step that initiated the async action. The "% in sql" is more than 100% though, that extra 82.4% is the time saved by doing the SQL in parallel.
Ideally I'd have the long running SQL query on the wait step rather than the init step, but I can't see a way to do that without changing the return type of the calling methods to explicitly pass around the timings (which would make the profiler considerably more obtrusive).
您可以做的是创建一个新的探查器并将其附加到网络探查器。
新的探查器在其声明中会有错误的时间,但步骤会没问题。
What you can do is to create a new profiler and attach it to the web one.
The new profiler will have wrong times in its declaration but the steps are gonna be ok.