繁体   English   中英

来自多个线程的度量标准

[英]Metrics from multiple threads

所以这似乎是一个非常常见的用例,也许我在考虑它,但我遇到了从多个线程保持集中度量的问题。 假设我有多个工作线程都处理记录,而我每1000个记录我想吐出一些指标。 现在我可以让每个线程记录单个指标,但随后获得吞吐量数字,但我必须手动添加它们(当然时间边界不准确)。 这是一个简单的例子:

public class Worker implements Runnable {

   private static int count = 0;
   private static long processingTime = 0;

   public void run() {
       while (true) {
          ...get record
          count++;
          long start = System.currentTimeMillis();
          ...do work
          long end = System.currentTimeMillis();
          processingTime += (end-start);
          if (count % 1000 == 0) {
              ... log some metrics
              processingTime = 0;
              count = 0;
          }
       }
    }
}

希望这有点道理。 另外我知道两个静态变量可能是AtomicInteger和AtomicLong。 但也许不是。 对人们有什么样的想法感兴趣。 我曾考虑过使用Atomic变量和使用ReeantrantReadWriteLock - 但我真的不希望指标停止处理流程(即指标对处理的影响非常小)。 谢谢。

将实际处理卸载到另一个线程可能是个好主意。 我们的想法是封装您的数据并将其快速交给处理线程,以便最大限度地减少对正在进行有意义工作的线程的影响。

存在小的切换争用,但是该成本通常比任何其他类型的同步小很多,在许多情况下它应该是一个很好的候选者。 我认为M. Jessup的解决方案非常接近我的,但希望下面的代码清楚地说明了这一点。

public class Worker implements Runnable {

   private static final Metrics metrics = new Metrics();

   public void run() {
      while (true) {
        ...get record
        long start = System.currentTimeMillis();
        ...do work
        long end = System.currentTimeMillis();
        // process the metric asynchronously
        metrics.addMetric(end - start);
     }
  }

  private static final class Metrics {
     // a single "background" thread that actually handles
     // processing
     private final ExecutorService metricThread = 
           Executors.newSingleThreadExecutor();
     // data (no synchronization needed)
     private int count = 0;
     private long processingTime = 0;

     public void addMetric(final long time) {
        metricThread.execute(new Runnable() {
           public void run() {
              count++;
              processingTime += time;
              if (count % 1000 == 0) {
                 ... log some metrics
                 processingTime = 0;
                 count = 0;
              }
           }
        });
      }
   }
}

我建议如果你不希望日志记录干扰处理,你应该有一个单独的日志工作线程,让你的处理线程只提供一些可以传递的值对象。 在示例中,我选择了LinkedBlockingQueue,因为它能够使用offer()阻塞一小段时间,并且您可以将阻塞推迟到另一个从队列中提取值的线程。 您可能需要在MetricProcessor中增加逻辑以根据您的要求对数据进行排序等,但即使是长时间运行的操作,也不会让VM线程调度程序在同一时间内不重新启动实际处理线程。

public class Worker implements Runnable {

  public void run() {
    while (true) {
      ... do some stuff
      if (count % 1000 == 0) {
        ... log some metrics
        if(MetricProcessor.getInstance().addMetrics(
            new Metrics(processingTime, count, ...)) {
          processingTime = 0;
          count = 0;
        } else {
          //the call would have blocked for a more significant
          //amount of time, here the results
          //could be abandoned or just held and attempted again
          //as a larger data set later
        }
      }
    }
  }
}

public class WorkerMetrics {
  ...some interesting data
  public WorkerMetrics(... data){
    ...
  }
  ...getter setters etc
}

public class MetricProcessor implements Runnable {
  LinkedBlockingQueue metrics = new LinkedBlockingQueue();
  public boolean addMetrics(WorkerMetrics m) {
    return metrics.offer(m); //This may block, but not for a significant amount of time.
  }

  public void run() {
    while(true) {
      WorkMetrics m = metrics.take(); //wait here for something to come in
      //the above call does all the significant blocking without
      //interrupting the real processing
      ...do some actual logging, aggregation, etc of the metrics
    }
  }
}

如果你依赖于count的状态和processingTime的状态是同步的那么你必须使用Lock。 例如,如果++count % 1000 == 0为true,则需要在此时评估processingTime的度量。

对于这种情况,使用ReentrantLock是有意义的。 我不会使用RRWL,因为实际上并没有发生纯读取的实例。 它始终是一个读/写集。 但你需要锁定所有

  count++
  processingTime += (end-start);
  if (count % 1000 == 0) {
      ... log some metrics
      processingTime = 0;
      count = 0;
  }

无论count ++是否会在那个位置,你还需要锁定它。 最后,如果您使用的是Lock,则不需要AtomicLong和AtomicInteger。 它只会增加开销,而且不会更加线程安全。

暂无
暂无

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

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