【问题标题】:I want a way where every one gets equal chance how do i do it in C#?我想要一种让每个人都有平等机会的方法我如何在 C# 中做到这一点?
【发布时间】:2011-04-18 18:09:32
【问题描述】:

我有一个函数,像这样,

private void Step()
{
    foreach (A a in aList)
        a.Act();
    foreach (B b in bList)
        b.Act();
    foreach (C c in cList)
        c.Act();
}

其中“a”获得第一次机会,“b”获得下一个机会,“c”获得最后一次机会,

我想要一种让每个人都有平等机会的方法,我如何在 C# 中做到这一点?

非常感谢大家的帮助!!!

【问题讨论】:

  • 机会均等是什么意思?你的意思是你想让它们同时运行?
  • 我想说的是使用线程,但 Brook 发布了一个很棒的实现作为答案。
  • 我很困惑,你想使用多个线程并行运行它们,还是只想在一个循环中运行它们?我们需要澄清一下。
  • 有人可以给我一个多线程的例子吗?

标签: c# logic equals


【解决方案1】:

我会定义一个接口IActable(选择你的名字)来定义Act()

public interface IActable
{
  void Act();
}

使 A、B 和 C 实现 IActable。然后,更改您的函数以执行以下操作。

private void Step()
{
    var all = new List<IActable>();
    all.AddRange(aList);
    all.AddRange(bList);
    all.AddRange(cList);
    all = all.Shuffle(new Random());

    foreach (IActable a in all)
    {
        a.Act();
    }
}

洗牌法,stolen from here

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
    T[] elements = source.ToArray();
    // Note i > 0 to avoid final pointless iteration
    for (int i = elements.Length-1; i > 0; i--)
    {
        // Swap element "i" with a random earlier element it (or itself)
        int swapIndex = rng.Next(i + 1);
        T tmp = elements[i];
        elements[i] = elements[swapIndex];
        elements[swapIndex] = tmp;
    }
    // Lazily yield (avoiding aliasing issues etc)
    foreach (T element in elements)
    {
        yield return element;
    }
}

使用plinq 的并行实现。 (订单未保留)

private void Step()
    {
        var all = new List<IActable>();
        all.AddRange(aList);
        all.AddRange(bList);
        all.AddRange(cList);

        all.AsParallel().ForAll(a=>a.Act());
    }

【讨论】:

  • 在这种情况下,原始列表中的项目将按照与原始 Step() 函数中相同的方式在 all 列表中排序。您应该重新排序/混合all 列表中的项目。或者只是从all 列表中选择随机项,调用Act() 并将其从列表中删除,直到all 列表不为空。
  • 我认为我在之前的笔记中添加的随机化技术应该更好,因为它不依赖于项目属性。谁知道如何比较不同的类,即使它们都实现了 IActable 接口。在这种情况下,所有项目的概率都相同。
  • @Elalfer:我在现实世界中很少看到随机是正确排序顺序的实例。我的直觉告诉我这里有一个字段可以排序,但这只是一个猜测。
  • @Brook:我有一个很好的例子。在最坏的情况下,快速排序可能会采用O(n^2),但通过简单的混合元素,最坏情况的概率可以降低到几乎为 0。;)
  • Fisher-Yates 洗牌很容易实现,它会给 O(n) 洗牌,也不需要修改对象以使 SortCriteria 属性随机化。
【解决方案2】:

ThreadPool.QueueUserWorkItem

来自文档页面的示例:

using System;
using System.Threading;
public class Example {
    public static void Main() {
        // Queue the task.
        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));

        Console.WriteLine("Main thread does some work, then sleeps.");

        // If you comment out the Sleep, the main thread exits, and
        // therefore the application ends, before the work item 
        // runs on the thread pool thread.  The thread pool uses background
        // threads, which do not keep the application running.  (This
        // is a simple example of a race condition.)
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    }

    // This method performs the work. It will be invoked in a thread
    // running in the .NET threadpool.
    static void ThreadProc(Object stateInfo) {
        // No state object was passed to QueueUserWorkItem, so 
        // stateInfo is null.
        Console.WriteLine("Hello from the thread pool.");
    }
}

在您的场景中,您可以简单地将各种列表中的所有工作项排队。不保证线程池的处理顺序。但是,如果要完成的工作相当“短”——也就是说,如果线程调度所需的时间“与”执行实际工作所需的时间“大致相同”——那么您可能需要重新调整操作,例如在所有线程池线程中提供更公平的机会。

如果您的操作运行时间较长(比如说几十秒或更长时间),那么线程池无论如何都会提供良好的公平性,并且假设线程之间没有争用,您可能不需要在对工作项进行排队之前对其进行洗牌.

【讨论】:

  • 你能举个例子吗?对于 ThreadPool.QueueUserWorkItem 和我的应用程序?我以前没用过,所以需要很多帮助
  • 当然,见上文。这直接来自我最初链接到的文档页面。
  • Threadpool 可以正常工作,使用 ThreadPool 和 plinq 之类的主要区别在于它在工作完成之前不会阻塞,除非您实现并维护等待句柄然后调用 WaitHandle.WaitAll(events)。我不知道这对您的实施是否重要。
【解决方案3】:

您可以使用多个线程并行运行所有这些方法(Cheeso 的回答) - 请注意,在这种情况下,绝对不能保证所有方法都会同时运行。在进入多线程方法之前,您应该定义“机会均等”在您的案例中的实际含义。

或者你需要决定你希望你的函数执行的顺序并做出适当的排序。 IE。分配优先级将所有内容放在同一个列表中(参见布鲁克的答案)并按优先级排序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 1970-01-01
    • 2021-04-15
    • 2021-09-07
    • 1970-01-01
    相关资源
    最近更新 更多