【问题标题】:How can I implement odd-even sorting in C# using threads?如何使用线程在 C# 中实现奇偶排序?
【发布时间】:2021-12-31 02:37:35
【问题描述】:

我正在练习 C# 中的线程和并发性,并尝试使用一个线程进行偶数排序和另一个线程进行奇数排序来实现基本的奇偶排序算法。

static bool Sort(int startPosition, List<int> list)
        {
            bool result = true;
            do
            {
                for (int i = startPosition; i <= list.Count - 2; i = i + 2)
                {
                    if (list[i] > list[i + 1])
                    {
                        int temp = list[i];
                        list[i] = list[i + 1];
                        list[i + 1] = temp;
                        result = false;
                    }
                }
            } while (!result);
            return result;
        }

而main方法是这样的:

static void Main(string[] args)
        {
            bool isOddSorted = false;
            bool isEvenSorted = false;

            List<int> list = new List<int>();
            while (list.Count < 15)
            {
                list.Add(new Random().Next(0, 20));
            }

            var evenThread = new Thread(() =>
            {
                isEvenSorted = Sort(0, list);
            });
            evenThread.Start();

            var oddThread = new Thread(() =>
            {
                isOddSorted = Sort(1, list);
            });
            oddThread.Start();

            while (true)
            {
                if (isEvenSorted && isOddSorted)
                {
                    foreach (int i in list)
                    {
                        Console.WriteLine(i);
                    }
                    break;
                }
            }

        }

可以理解,Sort 方法中的循环永远有效,因为结果变量永远不会设置为 true。然而,它的工作方式设法对列表进行排序。它只是不会随时中断。

但是,当我在 Sort 函数的 do-scope 的第一行添加“result = true”时,排序就搞砸了。

我不知道如何解决这个问题。

【问题讨论】:

  • 您的目标只是编写一个能正常工作的多线程奇偶排序实现,还是希望该实现比原始单线程实现更快地对数字进行排序?

标签: c# multithreading sorting parallel-processing


【解决方案1】:

查看您的result 变量以及您针对result 实现的逻辑。

外部do ... while (!result) 循环只会在resulttrue 时退出。

现在想象你的内部 for 循环找到两个需要交换的数字。所以它会交换数字。并将result 设置为false。这是我要问你的问题:当两个数字交换后,result 被设置为 falseresult 何时何地被设置为 true ?

此外,当您对偶数列表位置上的每个数字和奇数位置上的每个数字进行排序时,您的代码不会对整个列表进行最终排序。因此,基本上,如果在进行偶数和奇数排序之后,偶数位置 n 上的较大数字后面跟着奇数位置 n+1 上的较小数字,您的代码将保留它,使列表基本上保持静止(部分) 未排序...

【讨论】:

    【解决方案2】:

    您不能轻松地以多线程方式进行奇偶排序。为什么? 因为奇偶排序本质上是两次排序过程(奇数和偶数)的重复,任何后续的过程取决于前一个过程的结果。实际上,您不能并行/同时运行两个通道,因为每个通道必须跟随彼此。

    当然有使用多线程的方法,即使是奇偶排序,尽管这可能没有多大实际意义。例如,您可以将列表分成几个分区,每个分区独立地进行奇偶排序。每个分区的排序可以以多线程方式完成。作为最后一步,它需要以一种会产生完全排序列表的方式合并已排序的分区。

    (顺便说一句,如果您只让Sort 方法中的do while 循环运行很多次,那么您最终会得到一个排序列表,只要有足够的时间,即使“重叠”也是如此并发传递您最终会到达一个排序列表,但可能不是原始列表中的所有数字都相同。因为给定足够的循环重复次数,最终元素将相互比较并打乱到正确的位置。但是,由于您没有同步列表访问,您可能会从列表中丢失一些数字,被其他数字的副本替换,具体取决于两个线程之间列表访问的运行时行为和时间。)

    【讨论】:

    • "...您可以将列表分成几个分区,每个分区独立进行奇偶排序。":根据关于 @987654321 的维基百科文章@,这是一个相对较慢的算法,因此考虑到存在更有效的排序算法,对每个分区进行奇偶排序可能不是一个好主意。
    【解决方案3】:

    您正在尝试跨线程修改非线程安全集合。
    即使假设是好的 - 您在 Sort 方法中使用基本交换(但您没有完全正确地实现它),您必须考虑到当其中一个线程正在执行交换时,另一个线程可以交换一个在这一刻,temp 变量中的值。
    您需要熟悉locks 和/或thread-Safe Collections

    【讨论】:

    • @JeroenvanLangen 我对奇偶排序算法的理解,正如问题中的 OP 所描述的那样,一个线程对所有奇数进行排序,第二个线程对所有偶数进行排序。最终两个排序的子集由一个线程合并。我的理解可能有误。 Odd–even sort 似乎比这更多。但无论如何,我的假设是奇偶排序是一种无锁算法。这个答案建议使用锁定或同步集合,因此我不赞成。
    • 奇偶排序很好,但在这种情况下,当对一个线程进行排序时,当另一个线程处于temp 状态时可以移动一个值 - 最好的情况是它只是次优的分拣机。还有一种情况是List 是一个非线程安全的集合 - 虽然通过多个线程从它读取或多或少都可以,但修改它绝对不是 - 所以我将坚持我的答案一。
    • quain 您可以尝试根据您在每次交换时使用locking 的想法来实现并行奇偶排序算法,或者使用并发集合(我猜是ConcurrentDictionary)。如果您设法实现比单线程奇偶排序更快的东西,并且它基于这两个想法之一,并且内部没有使用任何其他排序算法,我承诺奖励 100 分赏金这个答案。我的期望是,任何这样的并行实现都会比非并行实现慢很多倍。它甚至不会接近。
    • 你是对的,在这种情况下并行算法有 95% 的可能性,即使在大型数据集上也会更慢 - 但我从未说过不会。我所有的答案都针对 Op 的代码——他已经在使用多个线程和一个非线程安全的集合(算法本身没有完全正确实现)——没有别的。我从来没有说过多线程会更快。
    • 我认为在使用多线程时更快是一种隐含的期望。我只是询问了 OP 以确保它。
    猜你喜欢
    • 2021-07-12
    • 2015-06-17
    • 2021-11-17
    • 2018-05-06
    • 1970-01-01
    • 2014-07-01
    • 2011-08-26
    • 1970-01-01
    • 2021-11-04
    相关资源
    最近更新 更多