12

我正在从事一个内存和计算密集型项目。执行的很大一部分使用了多线程FixedThreadPool。简而言之; 我有1 个BlockingQueue线程用于从多个远程位置(使用 URL 连接)获取数据并使用要分析的对象填充 a以及选择这些对象并运行分析的n 个线程。编辑:见下面的代码

现在这个设置在我运行 OpenSUSE 11.3 的 Linux 机器上运行起来就像一个魅力,但一位同事正在运行 Win7 的非常相似的机器上测试它,正在收到队列轮询超时的自定义通知(见下面的代码),实际上有很多。我一直在尝试监视她机器上的处理器使用情况,并且似乎软件没有获得超过 15% 的 CPU,而在我的机器上,处理器使用率达到了顶峰,正如我所期望的那样。

那么,我的问题是,这可能是队列“饥饿”的迹象吗?会不会是生产者线程没有获得足够的 cpu 时间?如果是这样,我该如何给池中的一个特定线程更高的优先级?

更新: 我一直在试图查明问题,但并不高兴……但我确实获得了一些新的见解。

  • 使用 JVisualVM 分析代码的执行表现出一种非常特殊的行为。这些方法在 CPU 时间的短时间内被调用,其间有几秒钟没有进展。对我来说,这意味着操作系统以某种方式在进程中踩刹车。

  • 禁用防病毒和备份守护程序对此事没有任何重大影响

  • 通过任务管理器(此处建议)更改 java.exe(唯一实例)的优先级也不会改变任何内容。(话虽这么说,我不能给java“实时”优先级,而不得不满足于“高”优先级)

  • 分析网络使用情况显示了良好的数据流入和流出,所以我猜这不是瓶颈(虽然它是流程执行时间的相当大一部分,但我已经知道并且几乎与我在我的 Linux 机器上得到了什么)。

关于 Win7 操作系统如何限制我的项目的 cpu 时间的任何想法?如果不是操作系统,那么限制因素可能是什么?我想再次强调,这台机器没有同时运行任何其他密集型计算,除了我的软件之外,cpus 上几乎没有负载。这真让我抓狂...

编辑:相关代码

public ConcurrencyService(Dataset d, QueryService qserv, Set<MyObject> s){

    timeout = 3;
    this.qs = qserv;
    this.bq = qs.getQueue();
    this.ds = d;
    this.analyzedObjects = s;
    this.drc = DebugRoutineContainer.getInstance();
    this.started = false;

    int nbrOfProcs = Runtime.getRuntime().availableProcessors();
    poolSize = nbrOfProcs;
    pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(poolSize);
    drc.setScoreLogStream(new PrintStream(qs.getScoreLogFile()));
}

public void serve() throws InterruptedException {
    try {
        this.ds.initDataset();
        this.started = true;
        pool.execute(new QueryingAction(qs));
        for(;;){
            MyObject p = bq.poll(timeout, TimeUnit.MINUTES);

            if(p != null){
                if (p.getId().equals("0"))
                    break;

                pool.submit(new AnalysisAction(ds, p, analyzedObjects, qs.getKnownAssocs()));
            }else 
                drc.log("Timed out while waiting for an object...");

        }

      } catch (Exception ex) {
            ex.printStackTrace();
            String exit_msg = "Unexpected error in core analysis, terminating execution!";

      }finally{
            drc.log("--DEBUG: Termination criteria found, shutdown initiated..");
            drc.getMemoryInfo(true);    // dump meminfo to log

            pool.shutdown();

            int mins = 2;
            int nCores = poolSize;
            long    totalTasks = pool.getTaskCount(), 
                    compTasks = pool.getCompletedTaskCount(),
                    tasksRemaining = totalTasks - compTasks,
                    timeout = mins * tasksRemaining / nCores;

            drc.log("--DEBUG: Shutdown commenced, thread pool will terminate once all objects are processed, " +
                        "or will timeout in : " + timeout + " minutes... \n" + compTasks + " of " +  (totalTasks -1) + 
                        " objects have been analyzed so far, " + "mean process time is: " +
                        drc.getMeanProcTimeAsString() + " milliseconds.");

            pool.awaitTermination(timeout, TimeUnit.MINUTES);
      }

}

该类QueryingAction是一个简单的类Runnable,它调用指定QueryService对象中的数据采集方法,然后填充一个BlockingQueue. 该类AnalysisActionMyObject.

4

8 回答 8

3

我怀疑生产者线程没有足够快地获取/加载源数据。这可能不是缺少 CPU,而是与 IO 相关的问题。(不知道为什么你的 BlockingQueue 有超时)

可能值得有一个线程定期记录添加的任务数量和队列长度(例如每 5-15 秒)

于 2011-12-19T11:03:55.037 回答
3

所以,如果我正确理解你的问题,你有一个线程来获取数据,还有几个线程来分析获取的数据。您的问题是线程没有正确同步以一起运行并充分利用处理器。

你有一个典型的生产者-消费者问题,一个生产者和几个消费者。我建议您重新编写您的代码,以便拥有几个独立的消费者线程,这些线程总是在等待资源可用,然后才运行。这样您就可以保证最大程度地使用处理器。

消费者线程:

while (!terminate)
{
    synchronized (Producer.getLockObject())
    {
        try
        {
            //sleep (no processing at all)
            Producer.getLockObject().wait(); 
        }
        catch (Exceptions..)
    }

    MyObject p = Producer.getObjectFromQueue(); //this function should be synchronized

    //Analyse fetched data, and submit it to somewhere...   
}    

生产者线程:

while (!terminate)
{
    MyObject newData = fetchData(); //fetch data from remote location

    addDataToQueueu(newData); //this should also be synchronized

    synchronized (getLockObject())
    {
        //wake up one thread to deal with the data
        getLockObject().notify();
    }
}

你看到这样,你的线程总是在执行有用的工作或休眠。这只是举例说明的草稿代码。在这里查看更多解释:http ://www.javamex.com/tutorials/wait_notify_how_to.shtml 和这里:http ://www.java-samples.com/showtutorial.php?tutorialid=306

于 2012-02-01T15:22:02.240 回答
1

优先级无济于事,因为问题不是决定谁获得宝贵资源的问题——资源使用没有最大化。生产者线程无法获得足够 CPU 时间的唯一方法是它没有准备好运行。优先级无济于事,因为问题不是问题。

机器有几个核心?生产者线程可能正在全速运行,但仍然没有足够的 CPU 运行。生产者也可能受 I/O 限制。

于 2011-12-19T11:06:08.397 回答
1

您可以尝试将生产者线程从池中分离出来(即创建一个不同的线程并将池Thread设置为当前容量为 -1),然后通过 将其优先级设置为最大值setPriority。看看会发生什么,尽管优先级很少能解释这种性能差异。

于 2011-12-19T11:08:56.173 回答
1

当您说 URL 连接时,您是指本地还是远程?可能是网络速度减慢了您的生产者的速度

于 2011-12-20T10:42:59.690 回答
1

因此,经过数周的摆弄、编码和其他类型的痛苦,我想我有了一个突破,如果你愿意的话,“一个清晰的时刻”......

我设法证明该程序可以在我的 Linux 机器上表现出同样的缓慢行为,并且确实可以在有问题的 Win-7 机器上全速运行。问题的症结似乎是用于存储先前查询结果的系统/缓存文件的某种损坏,总体而言,加快了分析速度。你一定会喜欢这个讽刺,在这种情况下,它们似乎是极端缓慢分析的原因。回想起来,我应该知道(奥卡姆剃刀)......

我仍然不确定损坏是如何发生的,但至少它可能与不同的操作系统无关。但是,使用我机器上的系统文件将 Win7 主机上的输出提高到大约 40%。更详细地分析该过程还表明,奇怪的是,Win7 上的 GC 活动明显更多,这显然需要大量 CPU 时间来处理数字。Giving-Xmx2g负责处理过多的垃圾收集,进程的 CPU 使用率飙升至 95-96%,线程运行平稳。

既然我最初的问题得到了回答,我不得不说,在 Linux 环境下,整体 java 的响应能力肯定更好,即使没有分配更多的堆内存,我也可以在后台运行广泛的分析时轻松地进行多任务处理。在 Win-7 中事情并不那么顺利,一旦分析全速开始,调整 GUI 的大小就会明显变慢。

感谢所有回复,对于部分误导性的问题描述,我深表歉意。我只是尽我所能分享我在调试时发现的东西。无论如何,我相信赏金属于 Peter Lawrey,因为他很早就指出了一个 I/O 问题,而正是他关于记录器线程的建议最终让我找到了答案。

于 2012-02-02T18:10:56.020 回答
0

我认为这是一些特定于操作系统的问题,因为这是两个单元之间的核心区别。更具体地说,某些东西减慢了通过远程连接到达的数据。

找到一些流量分析工具,例如Wireshark和/或Networx,并尝试发现是否有任何东西限制了 Win PC。也许它正在通过一个配置了某种速率上限的代理。

于 2012-02-01T11:44:26.893 回答
0

抱歉,这不是一个真正的答案,但不适合评论,我认为仍然值得一读:

  • 好吧,我对 JAVA 不友好
  • 但我最近对通过 USB 进行机器控制的 C++ 项目也有同样的问题。
  • 在 XP 或 W2K 上,在任何 2 核或更多核机器上运行数月的 24/7 运行完美无缺
  • 在 W7 和足够强大的机器上一切正常,但有时(每几个小时 cca 1x)在没有明显原因的情况下冻结几秒钟。
  • 在 W7 和相对较弱的机器(2 核 1.66GHz T2300E 笔记本电脑)上,线程冻结了一段时间并再次运行,导致 USB/WIN/App FIFO 不足/溢出并崩溃通信......
    • 似乎没有任何阻塞,但 W7 调度程序只是偶尔不将 CPU 分配给正确的线程。
    • 我认为 USB 驱动程序 (JUNGO) 通信冻结了这不是真的我测量了它,即使在冻结时也可以
    • 冻结时间约为每分钟一次 6-15 秒 cca。
    • 在线程循环中添加一些安全睡眠后,冻结时间缩短到大约 0.5 秒
    • 但仍然存在
    • 即使应用程序没有下/溢出 FIFO,Windows USB 驱动程序端也会这样做(每分钟几次,持续几毫秒)
  • exe/线程优先级和类的更改不会影响 W7 上的性能(在 XP、W2K 上正常工作)

如您所见,我们似乎很可能遇到同样的问题。就我而言:

  • 与 I/O 无关(当我用设备模拟替换 USB 线程时,它的行为相似)
  • 将睡眠添加到时间关键代码有很大帮助
  • 错误也存在于线程数少[2 快 (17ms) + 1 慢 (250ms) + 应用程序代码 = 4]
  • 我在 W7 慢速机器上的 CPU 消耗也不是 100%,而是大约 95%,这没关系,因为我到处都在睡觉
  • 我的应用程序使用大约 40-100MB 内存,但 CPU 计算要求很高......
    • 但它不能在慢得多的机器上安全运行
    • 但由于 USB 驱动程序连接和多设备支持,它至少需要 2 个内核
  • 我的下一步是添加某种执行时间记录/分析,以更详细地查看正在发生的事情
  • 并且很少重写发送/接收线程,看看它是否有帮助

当我学到一些新的/有用的东西时会添加它。

于 2013-11-21T08:27:23.363 回答