C# 如何编写代码来实现这些任务?

C# 如何编写代码来实现这些任务?,c#,C#,我想用C实现一些异步代码,但我不会写。给我一个提示 我有4个任务(任务0、任务1、任务2、任务3) 任务1在任务0之后 任务3在任务2之后 任务0和任务2可以并行 任务1和任务3只能逐个完成,即任务3之后的任务1或任务1之后的任务3 那么,如何在C代码中实现这些任务呢 以下代码是不完善的,因为任务1和任务3不应该是Pallael static Task WholeTask() { var tasks = new List<Task>(); tasks.Add(Ta

我想用C实现一些异步代码,但我不会写。给我一个提示

我有4个任务(任务0、任务1、任务2、任务3)

  • 任务1在任务0之后
  • 任务3在任务2之后
  • 任务0和任务2可以并行
  • 任务1和任务3只能逐个完成,即任务3之后的任务1或任务1之后的任务3
那么,如何在C代码中实现这些任务呢

以下代码是不完善的,因为任务1和任务3不应该是Pallael

static Task WholeTask()
{
    var tasks = new List<Task>();
    tasks.Add(Task0and1());
    tasks.Add(Task2and3());
    return Task.WhenAll(tasks);
}

static async Task Task0and1()
{
    await Task.Run(() => Method0());
    await Task.Run(() => Method1());
}

static async Task Task2and3()
{
    await Task.Run(() => Method2());
    await Task.Run(() => Method3());
}

static void Method0()
{
    Thread.Sleep(1000);
    Console.WriteLine("task 0 is completed");
}
static void Method1()
{
    Console.WriteLine("task 1 starts");
    Thread.Sleep(1000);
    Console.WriteLine("task 1 is completed");
}
static void Method2()
{
    Thread.Sleep(1000);
    Console.WriteLine("task 2 is completed");
}
static void Method3()
{
    Console.WriteLine("task 3 starts");
    Thread.Sleep(1000);
    Console.WriteLine("task 3 is completed");
}
static void Main(string[] args)
{
    WholeTask().Wait();
}
静态任务WholeTask()
{
var tasks=新列表();
tasks.Add(Task0and1());
tasks.Add(Task2and3());
返回任务。WhenAll(任务);
}
静态异步任务Task0and1()
{
等待任务。运行(()=>Method0());
等待任务。运行(()=>Method1());
}
静态异步任务Task2and3()
{
等待任务。运行(()=>Method2());
等待任务。运行(()=>Method3());
}
静态void方法0()
{
睡眠(1000);
Console.WriteLine(“任务0已完成”);
}
静态void方法1()
{
Console.WriteLine(“任务1启动”);
睡眠(1000);
Console.WriteLine(“任务1已完成”);
}
静态void方法2()
{
睡眠(1000);
Console.WriteLine(“任务2已完成”);
}
静态void方法3()
{
Console.WriteLine(“任务3启动”);
睡眠(1000);
Console.WriteLine(“任务3已完成”);
}
静态void Main(字符串[]参数)
{
WholeTask()等等();
}

以下是解决问题所需的构造块:

  • 任务0和1,以及链接任务2和3
  • 使用a保护任务1和3中的关键部分。这确保了它们不会并行执行

    • 我想这对你会有用的

      static void Main(string[] args)
          {
              var task0 = new Task(WorkWithSleep("task0"));
              var task1 = new Task(WorkWithSleep("task1"));
              var task2 = new Task(WorkWithSleep("task2"));
              var task3 = new Task(WorkWithSleep("task3"));
      
      
              var after0or2 = Task.WhenAny(task0, task2).ContinueWith(t =>
              {
                  if (if (task0 == t.Result)
                  {
                      Task.WhenAll(task2, task1).ContinueWith((tt) => task3.Start());
                      task1.Start();
                  }
                  else
                  {
                      Task.WhenAll(task0, task3).ContinueWith((tt) => task1.Start());
                      task3.Start();
                  }
              });
      
              task0.Start();
              task2.Start();
              var allwork = Task.WhenAll(task0, task1, task2, task3);
      
              allwork.Wait();
              Console.ReadLine();
          }
      
          public static Action WorkWithSleep(string name, int wait = 1000)
          {
              return () =>
              {
                  Console.WriteLine($"Work:{name} STARTED:{DateTime.Now.ToLongTimeString()}");
                  Thread.Sleep(wait); //This will simulate proccesor work
                  Console.WriteLine($"Work:{name} ENDED:{DateTime.Now.ToLongTimeString()}");
              };
          }
      
      你可以玩等待时间,看看这是否是你想要的。但我不推荐这样做,因为在进行处理器密集型工作时,许多优化都可以通过编写特定于案例的代码来完成,如果需要并行化,可能会花费太长时间,而且每次优化都很重要

      public static async Task MainAsync()
              {
                  var task0 = Task.Run(WorkWithSleep("task0",5000));
                  var task2 = Task.Run(WorkWithSleep("task2"));
      
                  var task0or2 = await Task.WhenAny(task0, task2);
      
                  if (task0or2 == task0)
                  {
                      WorkWithSleep("task1")(); //No need to do a run since the thred we are on in not buisy. and can just run on the same one
                      await task2;
                      WorkWithSleep("task3")();
                  }
                  else
                  {
                      WorkWithSleep("task3")();
                      await task0;
                      WorkWithSleep("task1")();
                  }
              }
      
      编辑:在重新编辑条件后进行了更改

      EDIT2:已从使用可变IsComplete更改为引用检查

      EDIT3:添加了一种正确的异步方式

      我有4项任务

      我将这些定义如下,因为更容易看到答案是如何工作的:

      Task Task0();
      Task Task1();
      Task Task2();
      Task Task3();
      
      任务1在任务0之后。任务3在任务2之后

      您可以使用
      wait
      组合(链接/链)任务:

      async Task Task0and1()
      {
        await Task0();
        await Task1();
      }
      
      async Task Task2and3()
      {
        await Task2();
        await Task3();
      }
      
      任务0和任务2可以并行

      使用
      Task.whalll
      进行异步并发:

      var task0and1 = Task0and1();
      var task2and3 = Task2and3();
      await Task.WhenAll(task0and1, task2and3);
      
      任务1和任务3只能逐个完成,即任务3之后的任务1或任务1之后的任务3

      对异步兼容锁使用
      信号量lim

      private SemaphoreSlim _mutex = new SemaphoreSlim(1);
      async Task Task0and1()
      {
        await Task0();
        await _mutex.WaitAsync();
        try { await Task1(); }
        finally { _mutex.Release(); }
      }
      
      async Task Task2and3()
      {
        await Task2();
        await _mutex.WaitAsync();
        try { await Task3(); }
        finally { _mutex.Release(); }
      }
      
      最终代码:

      private SemaphoreSlim _mutex = new SemaphoreSlim(1);
      async Task Task0and1()
      {
        await Task0();
        await _mutex.WaitAsync();
        try { await Task1(); }
        finally { _mutex.Release(); }
      }
      
      async Task Task2and3()
      {
        await Task2();
        await _mutex.WaitAsync();
        try { await Task3(); }
        finally { _mutex.Release(); }
      }
      
      async Task WholeTask()
      {
        var task0and1 = Task0and1();
        var task2and3 = Task2and3();
        await Task.WhenAll(task0and1, task2and3);
      }
      
      private object _mutex = new object();
      void Task0and1()
      {
        Task0();
        lock (_mutex) { Task1(); }
      }
      
      void Task2and3()
      {
        Task2();
        lock (_mutex) { Task3(); }
      }
      
      void WholeTask()
      {
        Parallel.Invoke(task0and1, task2and3);
      }
      

      仅当您的任务是实际的异步任务时,上述内容才适用。如果您的任务是同步任务,那么您应该使用上述同步任务。逐步地,这将是:

      我有4项任务

      我将这些定义如下:

      void Task0();
      void Task1();
      void Task2();
      void Task3();
      
      任务1在任务0之后。任务3在任务2之后

      您可以通过依次调用来组合(链接/链)函数:

      void Task0and1()
      {
        Task0();
        Task1();
      }
      
      void Task2and3()
      {
        Task2();
        Task3();
      }
      
      任务0和任务2可以并行

      使用
      Parallel
      或PLINQ实现并行。在这种情况下,由于我们要调用两个函数,
      Parallel.Invoke
      是自然选择:

      Parallel.Invoke(task0and1, task2and3);
      
      任务1和任务3只能逐个完成,即任务3之后的任务1或任务1之后的任务3

      使用
      lock
      进行互斥:

      private object _mutex = new object();
      void Task0and1()
      {
        Task0();
        lock (_mutex) { Task1(); }
      }
      
      void Task2and3()
      {
        Task2();
        lock (_mutex) { Task3(); }
      }
      
      最终代码:

      private SemaphoreSlim _mutex = new SemaphoreSlim(1);
      async Task Task0and1()
      {
        await Task0();
        await _mutex.WaitAsync();
        try { await Task1(); }
        finally { _mutex.Release(); }
      }
      
      async Task Task2and3()
      {
        await Task2();
        await _mutex.WaitAsync();
        try { await Task3(); }
        finally { _mutex.Release(); }
      }
      
      async Task WholeTask()
      {
        var task0and1 = Task0and1();
        var task2and3 = Task2and3();
        await Task.WhenAll(task0and1, task2and3);
      }
      
      private object _mutex = new object();
      void Task0and1()
      {
        Task0();
        lock (_mutex) { Task1(); }
      }
      
      void Task2and3()
      {
        Task2();
        lock (_mutex) { Task3(); }
      }
      
      void WholeTask()
      {
        Parallel.Invoke(task0and1, task2and3);
      }
      

      你不能简单地结合使用
      wait
      Task。什么时候
      ?你能给我举个例子吗?@indirect\u life欢迎使用堆栈溢出。请学习如何使用堆栈溢出,并阅读如何提高问题的质量。然后,你的问题是包含你的完整源代码,这些代码可以由其他人编译和测试。任务与“并行性”无关。有一个任务并行库可以帮助实现这一点。我编辑了代码。这是最小的可复制性吗?不是批评答案,而是出于好奇:你会建议锁定使用wait吗?@user1781290:不一般:它们是两种不同的工具,用于不同(但有时重叠)的用例。在OP的情况下,这似乎是确保(a)0+1和2+3可以尽可能高效地并行运行的最简单解决方案,但(b)1和3不能同时执行。如果你有一个只使用等待语句的解决方案,我很想看看它;请随意添加它作为竞争答案。请注意,不鼓励使用
      任务
      构造函数。有一些关于它的信息@Default God这家伙的博客又来了。他一手负责开始所有任务都必须有所有代码分析器放入的配置等待废话。我不建议在现实世界的应用程序中使用它,因为这只是POC,我可以用Task.Run重写它。这将是任务构造函数的完美用例。这个家伙的博客简直是胡说八道,因为“我写过无数的异步和并行应用程序,我从来没有遇到过这种情况。”如果你知道你在做什么,这不是一个不使用某些东西的好理由。@FilipCordas你知道他是一个真正使用异步、并行的人,而C#@ScottChamberlain中的多线程编程没有读过这本书,所以不能说它是好是坏。我能告诉你的是,在他的博客上,他把自己的观点当作事实,并用随机的理论例子来说明“永远不要做某事”。他的理由是它们只能用于创建委托任务,而不能承诺任务。他们不理解异步lambda。它们以“冷”或未启动的状态创建任务,这与所有现代任务API不同。不适用于此控制台应用程序,因为我确实希望创建委派任务,不希望执行异步Landa,并且我希望冷启动,因为一个任务不应先于另一个任务启动。@Sc