在这种多线程情况下如何编写干净的代码?

时间:2019-12-24 09:21:08

标签: c# multithreading

此代码效果很好,但看起来很糟糕。如何在这种情况下编写漂亮的代码?

您可以在操场上看它:https://dotnetfiddle.net/GUZni0

或以下代码:

using System;
using System.Collections.Generic;
using System.Threading;

public class Program
{
    static object valueLocker = new Object();
    static List<int> uidList;
    static int takeuid = -1;
    static int countThreads = 0;
    public static void Main()
    {
        for (;;) { 
        Console.WriteLine("Hello World");

        uidList = new List<int>();
        uidList.Add(0);
        uidList.Add(1);
        uidList.Add(2);
        uidList.Add(3);
        uidList.Add(4);
        countThreads = 0;
        for (int i = 0; i < 10; i++)
        {
            Thread thread = new Thread(TakeUidThread);
            thread.Start();
        }

线程完成后,每0.5秒检查一次主线程并获取新的uidList

        while (countThreads < 10)
        {
            Thread.Sleep(500);
        }
        Console.WriteLine("All threads finished");

        }
    }

    public static void TakeUidThread() 
    {
        var localuid = -1;

            while (localuid < uidList.Count)
            {
                // thread takes free uid
                lock (valueLocker)
                {
                    takeuid++;
                    localuid = takeuid;
                }

                if (localuid < uidList.Count && localuid != -1)
                {
                    DoSomeJob(uidList[localuid]);
                }

            }

Thread inc countThreads结尾

            lock (valueLocker)
            {
                countThreads++;
            }
    }
    private static void DoSomeJob(int uid)
    {

    }
}

2 个答案:

答案 0 :(得分:2)

好吧,您可以尝试使用 PLinq Parallel Linq),并摆脱lockThread等。< / p>

  using System.Linq;

  ...

  uidList
    .AsParallel()
    //.WithMergeOptions(ParallelMergeOptions.NotBuffered)
    //.AsOrdered()
    .ForAll(item => DoSomeJob(item));

答案 1 :(得分:1)

这是使用线程的一种非常糟糕的方法。启动线程是一件很繁重的事情,只有在执行一些核心计算时才被认为是一个好的解决方案。在多线程环境中工作时,需要在两个目标之间进行选择:

  • 您这样做是为了提高性能:您实际上做了很多CPU工作,其中包括一些算法复杂度,无法通过其他方法降低。它可以从对大集合的简单排序到非常复杂的解析算法(例如自然语言处理等)。
  • 您为输入/输出(I / O)进行操作:为许多客户端提供服务,大多数情况下,您等待来自其他端点(例如SQL Server,硬盘驱动器,网络接口)的结果或其他一些系统组件。

为提高性能,您可以这样做:

Parallel.ForEach(uidList, DoSomeJob);

这将创建重量级的Thread,并在某个时间点几乎消耗掉整个CPU的功能。

对于I / O,请执行以下操作:

private async Task DoSomeJob(int uid){ ... }

await Task.WhenAll(uidList.Select(DoSomeJob));

这将需要async样式的开发,但是Task是一个非常轻量的对象,并且您几乎看不到CPU达到甚至1%的水平,因为预计大多数时候您的任务除了等待某事发生,然后再发生某事,然后所有这些……等等,什么都不做。