实现线程以更快地构建Smith-Watermann矩阵

时间:2013-11-09 13:17:25

标签: c# multithreading matrix

我在C#中执行以下循环的线程时遇到问题:

        for (int i = 1; i < matrix.scoreMatrix.GetLength(0); i++)
        {

            for (int j = 1; j < matrix.scoreMatrix.GetLength(1); j++)
            {
                matrix.CalculateScore(i, j);
            }
        }

此循环将匹配数组填充到Smith Waterman算法中。这需要花费很多时间,因为我想改进填充矩阵的过程。

必须从左上角执行填充矩阵,因为根据位于上方和左侧的单元格计算以下单元格。

我的想法是利用这2-3个额外的线程来填充每个线阵列,如下图所示:

enter image description here

任何提示或类似安排都会非常有用。

我完成了这样的事情:

主要功能:

        int i = 0, t1_row=0, t2_row=0, t3_row=0, finished_lines=0;

        Thread t1 = new Thread(() => getnext1(matrix, i, t1_row, t2_row, t3_row, finished_lines));
        Thread t2 = new Thread(() => getnext2(matrix, i, t1_row, t2_row, t3_row, finished_lines));
        Thread t3 = new Thread(() => getnext3(matrix, i, t1_row, t2_row, t3_row, finished_lines));

        t1.Start();
        t2.Start();
        t3.Start();
        t1.Join();
        t2.Join();
        t3.Join();

线程功能:

    public static void getnext1(SWMatrix matrix, int i, int t1_row, int t2_row, int t3_row, int finished_lines)
    {
        do
        {
            for (int j = 1; j < matrix.scoreMatrix.GetLength(1); j++)
            {
                if (t1_row <= t3_row - 1 || finished_lines >= i - 2)
                {
                    matrix.CalculateScore(i, j);
                    t1_row++;
                }
                else
                {
                    j--;
                }
            }
            finished_lines++;
            i++;
            t1_row = 0;
        }
        while (i >= matrix.scoreMatrix.GetLength(0));
    }

    public static void getnext2(SWMatrix matrix, int i, int t1_row, int t2_row, int t3_row, int finished_lines)
    {
        do
        {
            for (int j = 1; j < matrix.scoreMatrix.GetLength(1); j++)
            {
                if (t2_row <= t1_row - 1 || finished_lines >= i - 2)
                {
                    matrix.CalculateScore(i, j);
                    t2_row++;
                }
                else
                {
                    j--;
                }
            }
            finished_lines++;
            i++;
            t2_row = 0;
        }
        while (i >= matrix.scoreMatrix.GetLength(0));
    }

    public static void getnext3(SWMatrix matrix, int i, int t1_row, int t2_row, int t3_row, int finished_lines)
    {
        do
        {
            for (int j = 1; j < matrix.scoreMatrix.GetLength(1); j++)
            {
                if (t3_row <= t2_row - 1 || finished_lines >= i - 2)
                {
                    matrix.CalculateScore(i, j);
                    t3_row++;
                }
                else
                {
                    j--;
                }
            }
            finished_lines++;
            i++;
            t3_row = 0;
        }
        while (i >= matrix.scoreMatrix.GetLength(0));
    }

查询执行时间延长至近两倍。但我也有线程工作的信息。如何优化此代码?有什么建议吗?我在一台带4个处理器的机器上测试它。

1 个答案:

答案 0 :(得分:1)

您编写的代码不正确。例如:存在一种竞争条件,其中多个线程可以同时递增finished_lines并产生错误的结果。您使用静态变量在线程之间进行通信的想法遇到了一个名为false sharing的问题,并且会降低性能。 [编辑:仔细查看您的代码,我发现您根本没有使用共享变量。你的代码永远无法工作。]

我认为你最好不要使用块或瓷砖而不是单行。如果您的瓷砖排列如下:

A B C D ...
B C D E ...
C D E F ...
D E F G ...
. . . . ...

然后,一旦计算完所有先前的图块,就可以并行计算具有相同标签(在相同的反对角线上)的所有图块,并且您根本不需要担心线程之间的同步。

这实际上比它需要的更具限制性。您需要的是波前算法。碰巧来自Microsoft的Samples for Parallel Programming with the .NET Framework包含一个ParallelExtensionsExtras项目,其中包括一个有效的波前算法实现。这使用.NET 4.0或更高版本的任务并行库。