如何在 groovy 中使用多线程访问 1000 个端点?

How to hit 1000 endpoints using multi threading in groovy?

我需要点击 端点超过 1000 次 以从网站获取一些数据。所以我阅读了一些使用 多线程 来实现它的教程。但是一次我只想使用 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();

我的 Groovy Class 名为 ScraperService实现 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 接口的 运行() 方法。

在Groovy/Grails中:

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

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'

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
    }
}

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

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

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

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

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

ExecutorService threadPool = Executors.newSingleThreadExecutor();

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

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