问题 使用带有异步方法的秒表


我有一些代码如下:

public void Start()
{
    var watch = new Stopwatch();
    watch.Start();

    Task.Factory.StartNew(MyMethod1);
    Task.Factory.StartNew(MyMethod2);

    watch.Stop();
    Log(watch.ElapsedMilliseconds);
    Task.Factory.StartNew(MyMethod3);
}

因为MyMethod1和MyMethod2被称为异步watch.Stop()在错误的时间被调用。我如何确保在MyMethod1和MyMethod2完成后调用和记录.Stop确保MyMethod3不必等待。

我想在我的Start()方法中保留所有秒表功能,而不是记录我的3种方法中的任何一种,即MyMethod1,MyMethod2和MyMethod3


10446
2017-10-15 12:37


起源



答案:


你可以使用 Task.Factory.ContinueWhenAll 方法。

watch.Start();
var t1 = Task.Factory.StartNew(MyMethod1);
var t2 = Task.Factory.StartNew(MyMethod2);
Task.Factory.ContinueWhenAll(new [] {t1, t2}, tasks => watch.Stop());

如果您的目标是.NET 4.5及更高版本,则还可以使用该方法 Task.WhenAll。它返回一个任务,该任务将在所有传递的Task对象完成后完成。

Task.WhenAll(t1, t2).ContinueWith(t => watch.Stop());

20
2017-10-15 12:47





您需要创建一个新的线程来处理日志记录问题。 此日志记录线程将等待 EventWaitHandle.WaitAll(threadsEventWaitHandles) 它将包含所有线程EventWaitHandles。 像这样的东西:

private void LoggingThread()
{
    var watch = new Stopwatch();
    watch.Start();

    EventWaitHandle.WaitAll(threadsEventWaitHandles);

    watch.Stop();
    Log(watch.ElapsedMilliseconds);
}

还有方法 MyMethod1, MyMethod2 他们完成后会向登录线程发出信号。 像这样的东西:

private void MyMethod1()
{
    //... your code
    EventWaitHandle.Set();
}

private void MyMethod2()
{
    //... your code
    EventWaitHandle.Set();
}

因此,您可以确保MyMethod3不必等待。


-2
2017-10-15 13:09



ContinueWhenAll() 更简单,也更有效。 - svick
@svick,你是对的,我不知道这种技巧。谢谢。 - Jacob


答案:


你可以使用 Task.Factory.ContinueWhenAll 方法。

watch.Start();
var t1 = Task.Factory.StartNew(MyMethod1);
var t2 = Task.Factory.StartNew(MyMethod2);
Task.Factory.ContinueWhenAll(new [] {t1, t2}, tasks => watch.Stop());

如果您的目标是.NET 4.5及更高版本,则还可以使用该方法 Task.WhenAll。它返回一个任务,该任务将在所有传递的Task对象完成后完成。

Task.WhenAll(t1, t2).ContinueWith(t => watch.Stop());

20
2017-10-15 12:47





您需要创建一个新的线程来处理日志记录问题。 此日志记录线程将等待 EventWaitHandle.WaitAll(threadsEventWaitHandles) 它将包含所有线程EventWaitHandles。 像这样的东西:

private void LoggingThread()
{
    var watch = new Stopwatch();
    watch.Start();

    EventWaitHandle.WaitAll(threadsEventWaitHandles);

    watch.Stop();
    Log(watch.ElapsedMilliseconds);
}

还有方法 MyMethod1, MyMethod2 他们完成后会向登录线程发出信号。 像这样的东西:

private void MyMethod1()
{
    //... your code
    EventWaitHandle.Set();
}

private void MyMethod2()
{
    //... your code
    EventWaitHandle.Set();
}

因此,您可以确保MyMethod3不必等待。


-2
2017-10-15 13:09



ContinueWhenAll() 更简单,也更有效。 - svick
@svick,你是对的,我不知道这种技巧。谢谢。 - Jacob


    public void Start()
    {
        var watch = new Stopwatch();
        watch.Start();

        Task.Factory.StartNew(MyMethod1);
        Task.Factory.StartNew(MyMethod2);

        Task.WaitAll(); // Wait for previous tasks to finish

        watch.Stop();
        Log(watch.ElapsedMilliseconds);
        Task.Factory.StartNew(MyMethod3);
    }

-3
2017-10-15 12:39



“......但要确保MyMethod3不必等待。” - WhileTrueSleep
+1,一个非常简单的解决方案。我正在思考 ContinueWith。 - Mike Perrenoud