Scala Akka-处理阻塞操作
我有一个使用Scala、Akka和Spray构建的应用程序。 在应用程序中,我有一个对外部bash脚本的阻塞调用。 它通过sys.process调用,平均运行时间约为100ms 我一直在使用Curl和apachebench测试应用程序,以获得一些性能指标。我还使用nanoTime()为sys.process调用本身计时 如果我使用一个Curl调用进行测试,应用程序将按预期执行,sys.process调用大约需要100毫秒 当我使用Apache Bench和多个同时请求来增加服务器上的负载时,sys.process调用开始急剧增加,从100ms增加到接近1000ms,具体取决于负载 通过阅读Scala文档,我认为这里的问题在于阻塞调用使用了执行上下文中的所有可用线程,这会降低性能 但我怎样才能最好地满足这一需求呢 我尝试创建一个自定义执行上下文,并在将来将调用包装起来Scala Akka-处理阻塞操作,scala,asynchronous,akka,spray,Scala,Asynchronous,Akka,Spray,我有一个使用Scala、Akka和Spray构建的应用程序。 在应用程序中,我有一个对外部bash脚本的阻塞调用。 它通过sys.process调用,平均运行时间约为100ms 我一直在使用Curl和apachebench测试应用程序,以获得一些性能指标。我还使用nanoTime()为sys.process调用本身计时 如果我使用一个Curl调用进行测试,应用程序将按预期执行,sys.process调用大约需要100毫秒 当我使用Apache Bench和多个同时请求来增加服务器上的负载时,sy
implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(100))
val future = Future {
blocking {
sys.process.Process(...),
new java.io.File("/var/...")).!!
}
}
然后,我必须等待将来使用onComplete完成,但这反过来似乎会阻塞线程,并且我看不到基于Apache Bench每秒报告的请求数的性能有任何明显的提高
上面的代码位于Actor类中的方法中,由receive方法调用
有谁能推荐我应该如何构造这段代码以增加线程的数量并尽可能减少阻塞代码所花费的时间吗?
i、 e.移交操作,完成后返回
谢谢我将异步响应以避免阻塞行为:
class MyActor extends Actor {
val exec = Executors.newFixedThreadPool(max_threads)
def recieve = {
case Request(file) => {
exec.submit(new Runnable() {
def run() {
sys.process.Process(...),
new java.io.File("/var/...")).!!
self ! Done(file) // dont block, respond asynchronously
}
})
}
case Done(file) => completeRequest(file)
}
}
我将异步响应以避免阻塞行为:
class MyActor extends Actor {
val exec = Executors.newFixedThreadPool(max_threads)
def recieve = {
case Request(file) => {
exec.submit(new Runnable() {
def run() {
sys.process.Process(...),
new java.io.File("/var/...")).!!
self ! Done(file) // dont block, respond asynchronously
}
})
}
case Done(file) => completeRequest(file)
}
}
不需要为此创建新线程
class MyActor extends Actor {
def recieve = {
case Request(file) => {
val process=sys.process.Process.....
self ! CheckProcess(process, file)
}
case CheckProcess(process, file)=>{
if(doUppkeep(process)){
self ! CheckProcess(process, file)
} else {
Done(file)
}
}
case Done(file) => completeRequest(file)
}
def doUpKeep(process):Boolean={
// Do wathever is needed to keep the external process running
// avoid looping since this pethod will be called again
// return true if process is still running.
}
}
如果需要,您可以对CheckProcess消息进行调度,而不只是将它们推送到消息队列中
self.context.system.scheduler.scheduleOnce(10 milliseconds, self, CheckProcess(process, file))
这将使流程表现得更好一些,但每个请求可能会变慢一些
此模式将使用的资源保持在最低限度,同时使舒尔的所有流程都得到充分利用。无需为此创建新线程
class MyActor extends Actor {
def recieve = {
case Request(file) => {
val process=sys.process.Process.....
self ! CheckProcess(process, file)
}
case CheckProcess(process, file)=>{
if(doUppkeep(process)){
self ! CheckProcess(process, file)
} else {
Done(file)
}
}
case Done(file) => completeRequest(file)
}
def doUpKeep(process):Boolean={
// Do wathever is needed to keep the external process running
// avoid looping since this pethod will be called again
// return true if process is still running.
}
}
如果需要,您可以对CheckProcess消息进行调度,而不只是将它们推送到消息队列中
self.context.system.scheduler.scheduleOnce(10 milliseconds, self, CheckProcess(process, file))
这将使流程表现得更好一些,但每个请求可能会变慢一些
这种模式将使用的资源减至最少,同时使舒尔的所有流程都得到充分利用。这很奇怪。如何使用
onComplete
?您的代码中是否有wait
语句?或者这个bash脚本是否可能使用一些共享资源,这样当您并行运行它时,它的运行时间就会增加?这很奇怪。如何使用onComplete
?您的代码中是否有wait
语句?或者这个bash脚本是否可能使用一些共享资源,这样当您并行运行它时,它的运行时间会增加?