using System.Diagnostics;
internal class Program
{
    private static string[] _resTableColumnsNames = new string[] { "m*m", "1 t", "2 t", "3 t", "4 t", "5 t", "6 t", "7 t", "8 t" };

    private static void Main(string[] args)
    {
        Console.WriteLine(string.Join("\t", _resTableColumnsNames));

        for (int i = 10; i < 10000; i *= 2)
        {
            var a = CreateMatrix(i, i);
            var b = CreateMatrix(i, i);

            List<long> times = new() { i };

            for (int j = 1; j <= 8; j++)
            {
                var sw = new Stopwatch();
                sw.Start();

                MultiplyMatrix(a, b, j);

                sw.Stop();
                times.Add(sw.ElapsedMilliseconds);
            }
            Console.WriteLine(string.Join("\t", times));
        }
    }

    /// <summary>
    /// Создаём матрицу случайных элементов 
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    private static int[,] CreateMatrix(int x, int y)
    {
        var rnd = new Random();

        var res = new int[y, x];

        for (int i = 0; i < y; i++)
        {
            for (int j = 0; j < x; j++)
            {
                res[i, j] = rnd.Next(0, 100);
            }
        }
        return res;
    }

    /// <summary>
    /// Вывести матрицу. Использовался при отладке
    /// </summary>
    /// <param name="mx"></param>
    private static void PrintMatrix(int[,] mx)
    {
        for (int i = 0; i < mx.GetLength(0); i++)
        {
            for (int j = 0; j < mx.GetLength(1); j++)
            {
                Console.Write($"{mx[i, j].ToString("000")}\t");
            }
            Console.WriteLine();
        }
    }

    /// <summary>
    /// Непосредственно умножение матриц
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="maxTask"></param>
    /// <returns></returns>
    private static int[,] MultiplyMatrix(int[,] a, int[,] b, int maxTask)
    {
        int[,] res = new int[a.GetLength(0), b.GetLength(1)];

        var semaphore = new SemaphoreSlim(maxTask, maxTask);

        for (int i = 0; i < a.GetLength(0); i++)
        {
            for (int j = 0; j < b.GetLength(1); j++)
            {
                semaphore.Wait();
                int ci = i;
                int cj = j;
                _ = Task.Run(() =>
                {
                    try
                    {
                        res[ci, cj] = CalculateElement(a, b, ci, cj);
                    }
                    finally
                    {
                        semaphore.Release();
                    }
                });
            }
        }
        semaphore.Wait(maxTask);
        return res;
    }

    /// <summary>
    /// Вычисление значение одного элемента 
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="i"></param>
    /// <param name="j"></param>
    /// <returns></returns>
    private static int CalculateElement(int[,] a, int[,] b, int i, int j)
            => Enumerable.Range(0, a.GetLength(1)).Sum(k => a[i, k] * b[k, j]);
}