【问题标题】:ManualResetEvent(EventWaitHandle) Set spends much cpu than WaitOne(timeout)ManualResetEvent(EventWaitHandle) Set 比 WaitOne(timeout) 花费更多的 cpu
【发布时间】:2014-03-19 15:51:03
【问题描述】:

在实现 ManualResetEvent 时,有些让我吃惊,

据我了解mre.Set() 命令信号并让其他进程执行。

mre.WaitOne(); 保持当前行并等待信号。除此之外,如果我们使用超时mre.WaitOne(100ms);

但是!让我们假设 StartCommunicate 是一个线程的工作。

如果我使用waitHandle.Set();,我的进程使用 ~%25 或另一个项目 ~%1 CPU 资源。

但是如果我使用waitHandle.WaitOne(100);(超时值是象征性的。它(尝试)等待信号100毫秒)。

进程开始使用 ~%0 CPU 资源 waitone(timeout) 这是什么意思 ? ThereIsAJobToExecute 对我来说是 Socket.HasData。那么这是否意味着对 SerialPort.BytesToReadSocket.Available 的访问次数过多会使我们的 CPU 使用率更高?

每次点击都将线程保持 100 毫秒对我有什么副作用吗?假设一个socket程序或者一个rs232连接波特率相对新一代PC来说是很低的。

所以使用mre.WaitOne(1); 对我来说似乎更可取。你怎么看待这件事 ?我正在用一些内存和性能分析器做一些实验,但我不确定我是否正在为各种客户端机器做最佳解决方案......

渴望你的cmets。

提前致谢!

    ManualResetEvent waitHandle = new ManualResetEvent(false);
    public void StartCommunicate()
    {
        while (true)
        {
            if (ThereIsAJobToExecute)
            {
                Execute the job here!
            }
            else {
                //waitHandle.Set();
                waitHandle.WaitOne(1);
            }                              
        }

    }

编辑: 对于 Socket 编程,ASYN 可以工作,所以我们可以通过下面的代码轻松完成,我们不需要轮询。

但是 RS232 COMM 端口编程我需要它。还是不行?

 do
 {
      socket.BeginReceiveASYN(....ReceiveCallBack,...,socket)
      mre.WaitOne();
      mre.Reset();
 }while(true)

     void ReceiveCallBack(IResult rst)
     {
     //get the socket and do my job here!
      mre.Set();
     }

【问题讨论】:

  • Set()WaitOne 很少可以互换。我不清楚你为什么认为他们在这种情况下。
  • 通常,任何生成“JobToExecute”的东西都会发出信号。这有点像线程间通信的要点——不需要轮询工作。
  • @MartinJames 我将编辑我的问题以使其更清楚。
  • @Damien_The_Unbeliever 你是对的,他们的工作是不同的。我刚刚注意到,通过 WaitOne,我可以减轻线程的负担,从而更有效地利用 CPU。我认为 com 端口轮询不需要太多 CPU。我正在尝试通过从 com 端口获取 1000 个字节,处理顺序字节来绘制实时图表……这才是真正的工作。我同意,这听起来很奇怪,但我正在尝试所有方法来实现这一点。
  • 比较苹果和橙子是不公平的。 SetWaitOne 是正交的。而且..顺便说一句,您的异步套接字代码正在浪费线程等待,因此您无法从异步中获得任何可伸缩性,因此使用同步套接字比让线程等待直到您收到数据要好。

标签: c# multithreading sockets event-wait-handle


【解决方案1】:

WaitOne 将线程置于挂起状态,这不会消耗 CPU 资源。来自ManualResetEvent 的信号稍后唤醒线程。

【讨论】:

    【解决方案2】:

    我不是 100% 清楚您使用 ManualResetEvent 的目的是什么。不过……

    waitHandle.WaitOne(1) 这样的操作几乎毫无意义,因为您的睡眠时间如此之短,以至于您实际上忙于等待该线程,并消耗没有做任何事情的 CPU 资源。

    如果您希望告诉您的线程它应该唤醒并处理数据,那么请尝试以下操作:

    while(true)
    {
      waitHandle.Wait();
      waitHandle.Reset();
    
      while(ThereIsAJobToExecute)
      {
        // Process the jobs
      }
    }
    

    这将使您的线程在无事可做时进入睡眠状态,并且不会浪费任何资源。现在您可以在有工作要做时使用waitHandle.Set() 发出信号。

    【讨论】:

    • 我认为如果 waitHandle 的状态为 false(如果您的意思是 waitone by wait),您的代码将无法工作。我想通过等待一段时间我只是做了一个计时器的睡眠工作。我这样做是为了避免轮询的 CPU 过度使用,而且我只是在没有工作的时候才这样做。如果有 SYNC 作业,它将完成该作业并再次轮询。但是没有工作让我们稍等一下再问。这就像“不要经常问我同样的问题”。它比 NOP 需要更多的时间。你在回答之前读过 cmets 吗?
    • 如果事件没有发出信号,那么线程将休眠直到发出信号。如果它没有工作来执行你希望它做什么而不是睡觉?你的问题不是很清楚你想要做什么,所以我做了一个最好的猜测。
    • 假设有一个轮询作业。您没有任何更改通知。然后你在一个连续的循环中询问它。但是确定是否有工作[这成为另一份工作]需要时间,而且不需要经常要求这种变化。顺便说一句,您很少会因为 - 不执行 IsThereAJobMethod- 而获得一些免费的 CPU 资源。我问这个问题是为了了解真正发生了什么。我认为大卫·哈尼是对的。
    • 我只是不知道将 SerialPort 的 DataReceived 事件用作通知。现在我的问题对于套接字编程或串口编程无效。我认为唯一的方式是轮询它,但不是。很抱歉造成误解。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多