Groovy中的批处理请求?
我是Groovy新手,对于如何将请求成批提交到服务器(而不是像我目前所做的那样单独提交到服务器)有点迷茫:Groovy中的批处理请求?,groovy,concurrency,Groovy,Concurrency,我是Groovy新手,对于如何将请求成批提交到服务器(而不是像我目前所做的那样单独提交到服务器)有点迷茫: class Handler { private String jobId // [...] void submit() { // [...] // client is a single instance of Client used by all Handlers jobId = client.add(args)
class Handler {
private String jobId
// [...]
void submit() {
// [...]
// client is a single instance of Client used by all Handlers
jobId = client.add(args)
}
}
class Client {
//...
String add(String args) {
response = postJson(args)
return parseIdFromJson(response)
}
}
现在,有东西调用Client.add,它将发布到RESTAPI并返回解析结果
我遇到的问题是,add方法可能会被快速连续调用数千次,收集传入add的所有arg将更加有效,等待add调用停止,然后为该批处理向restapi发布一次,一次性发送所有arg
这可能吗?add可能会立即返回一个假id,只要批处理发生,提交发生,客户端可以稍后知道假id和来自REST API的id之间的查找,REST API将按照发送给它的参数对应的顺序返回id。如注释中所述,对于GPAR来说,这可能是一个很好的例子,它在这类场景中非常出色 这实际上不是关于groovy,而是关于java和jvm中的异步编程 如果您想坚持使用java并发习惯用法,我将提供一段代码片段,您可以将其用作潜在的起点。这尚未经过测试,也未考虑边缘情况。我写这篇文章是为了好玩,因为这是异步编程,我还没有花适当的时间考虑它,所以我怀疑里面有足够大的洞可以让坦克通过 也就是说,下面是一些试图批量处理请求的代码:
import java.util.concurrent.*
import java.util.concurrent.locks.*
// test code
def client = new Client()
client.start()
def futureResponses = []
1000.times {
futureResponses << client.add(it as String)
}
client.stop()
futureResponses.each { futureResponse ->
// resolve future...will wait if the batch has not completed yet
def response = futureResponse.get()
println "received response with index ${response.responseIndex}"
}
// end of test code
class FutureResponse extends CompletableFuture<String> {
String args
}
class Client {
int minMillisLullToSubmitBatch = 100
int maxBatchSizeBeforeSubmit = 100
int millisBetweenChecks = 10
long lastAddTime = Long.MAX_VALUE
def batch = []
def lock = new ReentrantLock()
boolean running = true
def start() {
running = true
Thread.start {
while (running) {
checkForSubmission()
sleep millisBetweenChecks
}
}
}
def stop() {
running = false
checkForSubmission()
}
def withLock(Closure c) {
try {
lock.lock()
c.call()
} finally {
lock.unlock()
}
}
FutureResponse add(String args) {
def future = new FutureResponse(args: args)
withLock {
batch << future
lastAddTime = System.currentTimeMillis()
}
future
}
def checkForSubmission() {
withLock {
if (System.currentTimeMillis() - lastAddTime > minMillisLullToSubmitBatch ||
batch.size() > maxBatchSizeBeforeSubmit) {
submitBatch()
}
}
}
def submitBatch() {
// here you would need to put the combined args on a format
// suitable for the endpoint you are calling. In this
// example we are just creating a list containing the args
def combinedArgs = batch.collect { it.args }
// further there needs to be a way to map one specific set of
// args in the combined args to a specific response. If the
// endpoint responds with the same order as the args we submitted
// were in, then that can be used otherwise something else like
// an id in the response etc would need to be figured out. Here
// we just assume responses are returned in the order args were submitted
List<String> combinedResponses = postJson(combinedArgs)
combinedResponses.indexed().each { index, response ->
// here the FutureResponse gets a value, can be retrieved with
// futureResponse.get()
batch[index].complete(response)
}
// clear the batch
batch = []
}
// bogus method to fake post
def postJson(combinedArgs) {
println "posting json with batch size: ${combinedArgs.size()}"
combinedArgs.collect { [responseIndex: it] }
}
}
它应该可以工作并打印出从我们虚假的json提交中收到的响应 一切都是可能的,但你必须编写它…如果在相当长的时间内没有暂停,等待调用添加暂停可能会导致问题&你必须批处理1000个请求,可能需要根据时间和可配置的限制进行批处理。另外,如果您向呼叫者返回一个假id,那么会发生什么&其余的呼叫失败?猜测您将不得不撤销一堆刚刚标记为已完成的内容。也许可以看看GPAR和多线程技术。谢谢。我最终选择了另一种方式,因为我没有意识到在我的头顶上发生了并发,但如果我需要做类似的事情,这肯定会有助于理解。
~> groovy code.groovy
posting json with batch size: 153
posting json with batch size: 234
posting json with batch size: 243
posting json with batch size: 370
received response with index 0
received response with index 1
received response with index 2
...
received response with index 998
received response with index 999
~>