繁体   English   中英

计算每秒调用该方法的次数的最佳方法

[英]best way to count how many times per second the method is called

我有一个 dll 方法应该是“QoSed”——这个方法每秒最多调用 100 次。:

    private static extern int ExecTrans(int connectionId);

这个方法只在程序的一个地方用过,这个地方qos是可以的。 我需要为每个connectionId单独的“qos 计数器”。 所以ExecTrans(1)ExecTrans(2)应该去不同的计数器。

在第一次迭代时,我想计算调用方法的频率(对于每个connectionId )。 即我想要“实时统计”。 有两种方法:

- allow to exceed limitiation for a short period. for example allow "100 transaction from 0 to 1 second, 100 transaction from 1 to 2 seconds and 200 transactions from 0.5 to 1.5 second".
- at any second interval transactions should not exceed 100.

现在我不在乎使用这些方法中的哪一种,但我会选择一种减少“开销”的方法。 我希望 qos 尽可能少地添加“额外工作”,因为它是对每 0.1 毫秒敏感的交易软件。

至于第一种方法,我想我可以使用类似的方法(伪代码,可能statscurStats应该是线程安全的):

private int[] stats      // statistic to display to user
private int[] curStats;  // statistic currently collection

OnOneSecondElapsed(object source, ElapsedEventArgs args) {
    foreach (conId : connIds) {
        stats[conId] = curStats[conId];
        curStats[conId] = 0;
    }
}

myMethod {
    ......
    ExecTrans(conId);
    ++curStats[conId];
    ......
}

至于第二种方法......是否有可能制作一个集合,其中对象生命恰好一秒钟,一秒钟后消失? 然后每次我都会将下一个对象添加到集合中,除非集合包含 100 个对象。

你怎么认为? 我不熟悉 C# 库文件,所以可能我错过了一些有用的类,也许你可以建议另一种方法。

第一种方法:

  • 使用ConcurrentQueue<DateTime>
  • 在每次请求之前,检查队列的大小。 如果 > 100,则取消请求
  • 如果 < 100,则将当前 DateTime 入队并执行请求
  • 在后台线程中,每 0.1 秒删除一次早于 1 秒的条目

它应该相当有效,但是:

  • 由于在检查队列计数和入队时间之间没有锁定,因此有时每秒可能会收到略多于 100 个请求
  • 由于后台线程每 0.1 秒执行一次,如果您同时收到 100 个请求,它可能会阻塞队列长达 1.1 秒。 根据需要调整睡眠时间。

我可能是错的,但我认为没有完美的解决方案。 基本上,系统越精确,开销就越大。 您必须根据需要调整参数。

有一种称为分析器的工具可以完全满足您的需求。 你用你的代码运行它,它会确切地告诉你它在每个方法中花费了多少时间以及每个方法被调用了多少次。 这是一个关于 C# 分析器的旧线程 如果您是专业开发人员,您可能已经拥有分析器的公司许可证。

万一有人需要测量而不是节流......这是一种天真的方法,可以为您提供粗略的估计:

class A{
    private int _calls;
    private Stopwatch _sw;

    public A(){
       _calls = 0;
       _sw = new Stopwatch();
       _sw.Start();
    }

    public void MethodToMeasure(){
        //Do stuff
        _calls++;
        if(sw.ElapsedMilliseconds > 1000){
            _sw.Stop();
            //Save or print _calls here before it's zeroed
            _calls = 0;
            _sw.Restart();
        }
    }
}

在某些情况下,您每秒会被调用超过 n 次,我假设您只是不想在额外的情况下进行任何实际处理。

您可以使用同步 Q 对象来保存要为每个连接处理的事务。 调用您的方法只会将数据排入队列,说明应该做什么。 在单独的处理线程中(系统或每个连接只有一个),您可以将操作出列并以每 0.01 秒 1 的速率处理它们。 在为给定的连接排列每个工作单元之前,只需将 Q 大小截断为 100(向下弹出为 100),瞧,您会丢弃额外的工作项。

注意:您需要一个精确的计时功能来每 0.01 秒强制执行 1 个事务。 例如:

Stopwatch watch = new Stopwatch();
int nextPause = watch.Elapsed.Milliseconds + 10;
while (true)
{
    //do work (dequeue one item and process it)

    int now = watch.Elapsed.Milliseconds;
    if( now < nextPause ) {
        Thread.Sleep( nextPause - now );
    }
    nextPause = watch.Elapsed.Milliseconds + 10;
}

注意:如果事务花费的时间超过 10 毫秒(1/100 秒),您可能会删除额外的工作项...

如果您希望工作线程更加“突发”,您可以在一个循环中处理多个工作项并使用更长的等待时间,这将需要部分等待和部分“剩余项”计数。 (另外,最好使用 Monitor.Pulse 和 Montior.Wait 而不是 sleep ......)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM