備忘録

備忘録

C#で非同期かつ優先度考慮可能なQueueを利用する方法

Ⅰ. はじめに

タイトルの通り「C#で非同期かつ優先度考慮可能なQueueを利用する方法」です。
非同期ではないPriorityQueueは.NET6で実装されました

Ⅱ. やり方

1. 必要なパッケージをNuGetからインストールする
dotnet add package ConcurrentDataStructures --version 0.2.0
2. サンプルプログラムを書く

※簡単の為非同期らしい動きは省きます

using DataStructures;

namespace Test
{
  class Program
  {
    class MyQueue : IComparable<MyQueue>
    {
      public int Id { get; set; }
      public int Priority { get; set; }

      public int CompareTo(MyQueue x)
      {
        // Priorityが大きい順に取得出来るようにする
        return Priority - x.Priority;
      }
    }

    static void Main(string[] args)
    {
      var queue = new ConcurrentPriorityQueue<MyQueue>();
      queue.TryAdd(new MyQueue { Id = 1, Priority = 100 });
      queue.TryAdd(new MyQueue { Id = 2, Priority = 999 });
      queue.TryAdd(new MyQueue { Id = 3, Priority = 200 });

      while (true)
      {
        if (queue.TryTake(out var x))
        {
          Console.WriteLine($"Id: {x.Id}, Priority: {x.Priority}");
        }
        else
        {
          break;
        }
      }
    }
  }
}

実行結果

Id: 2, Priority: 999
Id: 3, Priority: 200
Id: 1, Priority: 100

留意点(2022/08/18追記)

  • 以下プログラムは途中でID5を挿入する。このときID2よりもID5が先に取り出される。
    つまり、CompareToの条件が最優先される。
    (Queueの動きとして妥当では無い気もしますが…)
using DataStructures;
using System;

namespace Test
{
  class Program
  {
    class MyQueue : IComparable<MyQueue>
    {
      public int Id { get; set; }
      public int Priority { get; set; }

      public int CompareTo(MyQueue x)
      {
        // Priorityが大きい順に取得出来るようにする
        return Priority - x.Priority;
      }
    }

    static void Main(string[] args)
    {
      var queue = new ConcurrentPriorityQueue<MyQueue>();
      queue.TryAdd(new MyQueue { Id = 1, Priority = 100 });
      queue.TryAdd(new MyQueue { Id = 2, Priority = 100 });
      queue.TryAdd(new MyQueue { Id = 3, Priority = 999 });
      queue.TryAdd(new MyQueue { Id = 4, Priority = 200 });

      while (true)
      {
        if (queue.TryTake(out var x))
        {
          Console.WriteLine($"Id: {x.Id}, Priority: {x.Priority}");

          if (x.Id == 4)
          {
            queue.TryAdd(new MyQueue { Id = 5, Priority = 100 });
          }
        }
        else
        {
          break;
        }
      }
    }
  }
}