【问题标题】:How to hit 1000 endpoints using multi threading in groovy?如何在 groovy 中使用多线程访问 1000 个端点?
【发布时间】:2019-06-08 09:12:21
【问题描述】:

我需要点击端点超过 1000 次才能从网站获取一些数据。所以我阅读了一些教程来使用 Multi Threading 来实现它。但一次我只想在同一方法上使用 13 个线程

所以基本上我使用 ExecutorService 一次运行 13 个线程:

ExecutorService threadPool = Executors.newFixedThreadPool(13);
for (int itLocation = 0; itLocation < locationList.size(); itLocation++) {
  //some code like
  ScraperService obj = new ScraperService(threadName,url)
  threadPool.submit(obj);
}
threadPool.shutdown();

我的名为 ScraperService 的 Groovy 类正在实现 Runnable 接口

@Override
        void run() {
            println("In run method...................")
            try {
                Thread.sleep(5000);
                someMethod()
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

问题:

我的问题是我的ExecutorService.submit(obj)ExecutorService.execute(obj) 没有调用我的Runnable 接口的run() 方法。

在 Groovy/Grails 中:

还有一个执行器插件Executor Plugin in grails,但我没有找到任何合适的示例如何使用它。

【问题讨论】:

  • 你为什么不使用threadPool.invokeAll(tasks);?但就您而言,我认为您必须致电threadPool.awaitTermination()
  • 我现在不关心 threadPool.invokeAll(tasks);

标签: multithreading grails groovy threadpool executorservice


【解决方案1】:

threadPool.submit 不执行任务

使用threadPool.execute(obj)threadPool.submit(obj).get()

而不是threadPool.submit(obj)

查看文档了解详情:

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#submit(java.util.concurrent.Callable)

示例:

import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


ExecutorService pool=Executors.newFixedThreadPool(3)

for(int i=0;i<7;i++){
    int x=i;
    Thread.sleep(444);
    pool.execute{
        println "start $x"
        Thread.sleep(3000+x*100);
        println "end   $x"
    }
}

println "done cycle"
pool.shutdown()                 //all tasks submitted
while (!pool.isTerminated()){}  //waitfor termination
println 'Finished all threads'

【讨论】:

  • 所以如果我想执行 1000 个线程,那么对于每个线程我应该使用 hdPool.submit(obj).get()。实际上也使用 threadPool.execute(obj) 方法,我的调用不会覆盖 run() 方法。
  • 如果您使用 execute(),您将无法判断您的可运行文件是否已运行。使用 submit(),您应该保存所有返回的 Futures,然后在它们上循环检查 get()。注意 InterruptedExceptions。 Guava 的 Futures.getUnchecked() 在这里可以提供很大的帮助。
【解决方案2】:

GPars 非常适合这类事情。

你的 ScraperService 可以像下面那样负责处理抓取的数据,或者也可以获取它,无论如何。

import groovyx.gpars.GParsPool

def theEndpoint = 'http://www.bbc.co.uk'

def scraperService

GParsPool.withPool( 13 ) {
    (1..1000).eachParallel {
        scraperService.scrape theEndpoint.toURL().text
    }
}

【讨论】:

    【解决方案3】:

    首先,我认为带有@Transnational 注释的groovy 服务 类存在问题,它不允许调用Runnable 接口的run() 方法。如果您要删除 @Transnational,那么它将调用 run() 方法。它也发生在我的案例中。但我不确定,可能还有其他原因。可以直接使用:

    ExecutorService threadPool =  Executors.newFixedThreadPool(13)
    threadPool.execute(new Runnable() {
                                @Override
                                void run() {
                                    Thread.sleep(5000);
                                    someMethod()
                                }
                            })
    

    额外(当我阅读您的问题时)

    如果您在同一方法上使用多个线程,则可能会很复杂,因为所有线程都将使用该方法的相同局部变量,这可能会出现问题。最好将多个线程用于不同的不同工作。

    但是如果你想使用相同的方法来执行多个线程,那么在我的场景中最好使用Executors.newSingleThreadExecutor()

    ExecutorService threadPool = Executors.newSingleThreadExecutor();
    

    newSingleThreadExecutor() 调用单个线程,因此如果您想在其上执行多个任务,那么它不会创建多个线程。相反,它会等待一个任务完成,然后再在同一线程上启动下一个任务。

    速度: newSingleThreadExecutor 与多线程相比会更慢但使用起来更安全。

    【讨论】:

      猜你喜欢
      • 2021-11-21
      • 1970-01-01
      • 2013-02-26
      • 2021-04-27
      • 1970-01-01
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      • 2016-08-12
      相关资源
      最近更新 更多