【问题标题】:How to use threading or Task pattern in following scenario如何在以下场景中使用线程或任务模式
【发布时间】:2014-01-20 14:31:18
【问题描述】:

我有两种方法在 Main 方法中使用,像这样

public bool isBadMethod() 
{ 
   bool isBad = Method1();
   if(isBad) return true; 
   else return Method2(); 
}

bool Method1() { ..... return true or false }         
bool Method2() { ..... return true or false }

如果 Method1 或 Method2 中的任何一个返回 true 不需要检查其他方法,我们可以将 MainMethod 返回为 true。但是,如果第一种方法返回 false,则需要检查第二种方法并最终返回第二种方法返回的任何内容。这里 Method1 和 Method2 是耗时的方法。我可以在这些方法上使用异步编程吗?帮忙怎么办。 (我使用的是 .net 4.0)

【问题讨论】:

  • 理论上你可以开始两个不同的任务。然后如果 Method1() 返回 true,则取消 Method2();否则等待 Method2() 完成。这取决于您可以取消 Method2()

标签: c# multithreading


【解决方案1】:

你可以利用表达式的短路:

bool val = Method1() || Method2();

如果Method1 返回true,则不会打扰第二种方法。

显然,如果方法调用开销很大,则继续执行任务路由,因为这不是并行执行。我只是发布这个以防万一它是一个 XY 问题。


使用任务,这可能是您想要的。它将运行这两种方法,然后只使用一个表达式来获取正确的结果。在这种情况下,它等待整整 3 秒来获取Method2 的结果。这也会取消。我不确定所使用的类型是否是最佳实践,因为我的经验并不完整,但它可以在我的沙箱中完成工作:
internal class Program
{
    private static void Main(string[] args)
    {
        var cm2 = new CancellationTokenSource();

        var m1 = Task.Factory.StartNew(() => Method1());
        var m2 = Task.Factory.StartNew(() => Method2(cm2.Token), cm2.Token);

        var val = m1.Result || m2.Result;

        cm2.Cancel();

        Console.WriteLine(val);
        Console.ReadLine();
    }

    private static bool Method1()
    {
        Thread.Sleep(1000);
        Console.WriteLine(1);
        return true;
    }

    private static bool Method2(CancellationToken token)
    {
        Thread.Sleep(3000);

        if (token.IsCancellationRequested)
            return false;

        Console.WriteLine(2);
        return true;
    }
}

正如 Matthew Watson 在 cmets 中指出的那样,Method2 需要使用取消令牌才能真正“取消”。在我的示例中,它只是停止打印数字并提前返回。

【讨论】:

  • 与我的答案非常相似 - 但我输入得太慢了。 :) 我只想指出取消令牌必须在任务方法中实际使用,否则它不会做任何事情。
  • cm1.Cancel(); 似乎没有必要,它仍然是从左到右的 eval。
  • @HenkHolterman 是的,我没有看到这一点,因为我人为的例子让左边比右边快(哦,生活在一个更简单的世界里)。改了。
  • @MatthewWatson Fair catch,我会记下来的。
【解决方案2】:

如果您不在乎 Method2() 在 Method1() 返回后是否继续运行,那么执行以下操作并不难:

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    internal class Program
    {
        private void run()
        {
            Stopwatch sw = Stopwatch.StartNew();
            bool result = test();
            Console.WriteLine("Returned " + result + " after " + sw.Elapsed);
        }

        private bool test()
        {
            var method1 = Task.Run(new Func<bool>(Method1));
            var method2 = Task.Run(new Func<bool>(Method2));

            return method1.Result || method2.Result;
        }

        public bool Method1()
        {
            Console.WriteLine("Starting Method1()");
            Thread.Sleep(2000);
            Console.WriteLine("Returning from Method1()");
            return true;
        }

        public bool Method2()
        {
            Console.WriteLine("Starting Method2()");
            Thread.Sleep(3000);
            Console.WriteLine("Returning true from Method2()");
            return true;
        }

        private static void Main()
        {
            new Program().run();
        }
    }
}

Method1() 需要 2 秒才能完成。 Method1() 需要 3 秒才能完成。

当您在 Method1() 设置为返回 true 的情况下运行它时,总时间约为 2 秒 - 这是 Method1() 的运行时间。

如果编辑 Method1() 使其返回 false,则总时间约为 3 秒 - Method2() 的运行时间。

因此您可以看到它没有按顺序运行这两个任务。这种方法是“推测执行”的一种形式。

但是,如果必须在 Method1() 返回 true 时取消 Method2(),则变得更加复杂。

【讨论】:

    【解决方案3】:

    使用任务,您的逻辑可以这样执行:

    System.Threading.Tasks.Task.Factory                     
        .StartNew<bool>(        
            () => {  return Method1(); })        
        .ContinueWith<bool>(prev =>        
            {                        
                if (!prev.Result)                                
                    return Method2();
                else
                    return true;         
            })
        .ContinueWith(prev =>        
            {                        
                // do something with prev.Result
            })
    

    请注意,您可以在第二个任务中执行第三个任务的逻辑,甚至可以在一个任务中执行所有任务,这取决于您的要求。例如,您可能需要将第三个任务与您的 UI 同步。

    【讨论】:

      猜你喜欢
      • 2020-05-17
      • 1970-01-01
      • 2021-05-28
      • 1970-01-01
      • 1970-01-01
      • 2017-07-04
      • 2019-05-24
      • 1970-01-01
      • 2018-06-25
      相关资源
      最近更新 更多