• 近期关于Thread使用的一些感想.


    最近项目一直在研究Thread问题,在客户端大量登陆时,或者大量请求时,会偶尔出现等待,甚至超时现象,和朋友通过性能监视器,查看服务器cpu,call per second等指标,发现在高峰时,cpu不稳定,线程加载慢,造成等待,通讯超时等问题,然后研究了一些关于Thread问题,得到了一些体会,感想.
    1.Thread在达到设置的MinWorkerThreadsPerCore后,线程数量会以两个的两个加载,一般在启动服务前我们会先设置线程数,代码如下:

    int minWorkerThreadsPerCore=100;
    int minIOThreadsPerCore=100;
    int maxWorkerThreadsPerCore=1000;
    int maxIOThreadsPerCore=1000;
    ThreadPool.SetMinThreads(minWorkerThreadsPerCore * Environment.ProcessorCount, 
                    minIOThreadsPerCore * Environment.ProcessorCount);
    ThreadPool.SetMaxThreads(maxWorkerThreadsPerCore * Environment.ProcessorCount,
                    maxIOThreadsPerCore * Environment.ProcessorCount);

    2.启动异步线程有多种方法.
    (1)在创建托管的线程时,在该线程上执行的方法将通过一个传递给 Thread 构造函数的 ThreadStart 委托或 ParameterizedThreadStart 委托来表示。在调用 System.Threading.Thread.Start 方法之前,该线程不会开始执行。执行将从 ThreadStart 或 ParameterizedThreadStart 委托表示的方法的第一行开始。

    Thread thread = new Thread(new ThreadStart(ThreadTestMethod));
    thread.Start(); 
    
    static void ThreadTestMethod()
         {
               Console.WriteLine("Test成功");
         }

    (2)调用 StartNew 在功能上等效于创建任务使用其构造函数之一来调用 Start 计划它的执行。

    Task.Factory.StartNew(ThreadTestMethod);

    (3)在线程池中执行

    ThreadPool.QueueUserWorkItem(o => ThreadTestMethod());

    (4)通过BeginInvoke,EndInvoke来调用,接收

    var handle = new SumDelegate(Sum);            
    IAsyncResult handleResut = handle.BeginInvoke(2, 3, null, null);
    var result = handle.EndInvoke(handleResut);
         
    public delegate int SumDelegate(int x, int y);
    
    static int Sum(int x, int y)
       {
           return x + y;
       } 

    (5)通过实体类嵌套委托

    var test = new Test();
    test.X = 4;
    test.Y = 5;
    test.MethodCompleted = new MethodCompleteCallback(WriteResult);
    Thread thread1 = new Thread(new ThreadStart(test.MyStartingMethod));
    thread1.Start();
    
    static void WriteResult(Test test)
        {
             Console.WriteLine(test.S);
        }
    
    public delegate void MethodCompleteCallback(Test test);
    public class Test
        {
             public int X { get; set; }
    
             public int Y { get; set; }
    
             public int S { get; set; }
             public MethodCompleteCallback MethodCompleted;
             public void MyStartingMethod()
             {
                  this.S = this.X + this.Y;
    
                  // 函数已经执行完了,调用另外一个函数。
                  this.MethodCompleted(this);
              }
          } 

    然后想到了一个问题,delegate如果参数和eventhandle一致也是object和EventArgs,能否相互转换,很可惜,微软未封装相关方法,经过网上资料查询,找到了Artech's blog中有提到相关转换,其具体思路是使用 DynamicMethod 类在运行时生成和执行方法

    DynamicMethod method = new DynamicMethod("WrappedEventHandler", null, paramTypes);
    MethodInfo invoker = paramTypes[0].GetMethod("Invoke");
    ILGenerator il = method.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Ldarg_2);
    if(!sourceParameters[1].ParameterType.IsAssignableFrom(destinationParameters[1].ParameterType))
    {               il.Emit(OpCodes.Castclass,sourceParameters[1].ParameterType);
    }
    il.Emit(OpCodes.Call, invoker);
    il.Emit(OpCodes.Ret);
    return method.CreateDelegate(eventHandlerType, eventHandler);

    写了这么多,突然有一天想到了一个很奇怪的问题,多线程的本质究竟是什么?Thread.Sleep(0)有什么作用?

    然后就研究了一下windows操作系统线程的优先级问题。

    操作系统中Windows是一种所谓的抢占式操作系统,就是说如果一个进程得到了 CPU 时间,除非它自己放弃使用 CPU ,否则将完全霸占 CPU ,直到操作系统发现某个线程长时间霸占CPU,会强制使这个线程挂起。

    在抢占式操作系统中,假设有若干进程,操作系统会根据他们的优先级,给他们算出一 个总的优先级来。操作系统就会把 CPU 交给总优先级最高的这个进程。当进程执行完毕或者自己主动挂起后,操作系统就会重新计算一 次所有进程的总优先级,然后再挑一个优先级最高的把 CPU 控制权交给他。

    因此,Thread.Sleep(0)的作用,就是“触发操作系统立刻重新进行一次CPU竞争”。竞争的结果也许是当前线程仍然获得CPU控制权,也许会换成别的线程获得CPU控制权。这也是我们在大循环里面经常会写一句Thread.Sleep(0) ,因为这样就给了其他线程比如Paint线程获得CPU控制权的权力,这样界面就不会假死在那里。

    而Thread.Sleep(2000)或以上时,又会发现一个新问题,当线程失效后,并不会马上gc,会一直占用着,等到下一个请求到来,并且线程数达到最大时,才会主动回收。

  • 相关阅读:
    为蓝桥杯准备
    Java里子类调用父类构造方法问题
    boost库的Singleton的实现以及static成员的初始化问题
    VS2005调试小记
    <转载>程序员每天该做的事
    vs2005, 2008 使用了未初始化的msg变量
    转载 vs2005 快捷键大全
    VS2005右键点击转到定义后出现“未定义符号”的提示及其解决
    软件工程配置规范(VC2005) 第二版(转载)
    匆忙赶路的时候别忘了适时停下来回头看看
  • 原文地址:https://www.cnblogs.com/gavinhuang/p/2960454.html
Copyright © 2020-2023  润新知