2011-06-24 5 views
7

मान लीजिए मुझे कई सीपीयू-बाध्य कार्यों को सक्रिय करना है। अगर मेरे पास 4 सीपीयू हैं, उदाहरण के लिए, मैं शायद कतार में प्रतीक्षा करने वाले 4-5 कार्यकर्ता धागे का एक निश्चित आकार का थ्रेड पूल बनाउंगा और कार्यों को कतार में रखूंगा। जावा में मैं इस तंत्र को लागू करने के लिए java.util.concurrent (शायद ThreadPoolExecutor) का उपयोग कर सकता हूं।स्कैला कलाकारों के साथ सीपीयू-बाध्य कार्यों को निष्पादित करना?

स्कैला कलाकारों के साथ आप इसे कैसे कार्यान्वित करेंगे?

+0

क्या आपने स्कैला अभिनेताओं या समांतर संग्रहों की कोशिश की है? वे पहले से ही विभिन्न सीपीयू पर वर्कलोड वितरित कर सकते हैं। अगर आपको अधिक नियंत्रण की आवश्यकता है तो आप अक्का में देख सकते हैं। – Fabian

उत्तर

9

सभी कलाकार मूल रूप से धागे हैं जिन्हें हुड के नीचे शेड्यूलर द्वारा निष्पादित किया जाता है। शेड्यूलर आपके कोर के मोटे तौर पर बाध्य कलाकारों को निष्पादित करने के लिए एक थ्रेड पूल बनाता है। इसका मतलब यह है कि आप बस काम प्रति एक अभिनेता आप निष्पादित और स्काला के बाकी छोड़ने की जरूरत बना सकते हैं:

for(i <- 1 to 20) { 
    actor { 
    print(i); 
    Thread.sleep(1000); 
    } 
} 

नुकसान यहाँ कार्यों की संख्या, प्रत्येक कार्य के लिए एक धागा बनाने की लागत पर निर्भर करता है हो सकता है काफी महंगा हो क्योंकि जावा में धागे इतने सस्ते नहीं हैं।

कार्यकर्ता अभिनेताओं की एक घिरे पूल बनाने और उसके बाद संदेश के माध्यम से उन्हें कार्य वितरित होगा कुछ की तरह करने के लिए एक आसान तरीका:

import scala.actors.Actor._ 

val numWorkers = 4 
val pool = (1 to numWorkers).map { i => 
    actor { 
    loop { 
     react { 
     case x: String => println(x) 
     } 
    } 
    } 
} 

for(i <- 1 to 20) { 
    val r = (new util.Random).nextInt(numWorkers) 
    pool(r) ! "task "+i 
} 

कारण है कि हम कई अभिनेताओं का निर्माण करना चाहते है, क्योंकि एक भी अभिनेता प्रक्रियाओं आपके कार्यों के लिए समांतरता प्राप्त करने के लिए एक समय में केवल एक संदेश (यानी कार्य) आपको एकाधिक बनाने की आवश्यकता है।

एक साइड नोट: जब I/O बाध्य कार्यों की बात आती है तो डिफ़ॉल्ट शेड्यूलर विशेष रूप से महत्वपूर्ण हो जाता है, क्योंकि आप निश्चित रूप से उस मामले में थ्रेड पूल के आकार को बदलना चाहते हैं। इसके बारे में विवरण में जाने वाले दो अच्छे ब्लॉग पोस्ट हैं: Explore the Scheduling of Scala Actors और Scala actors thread pool pitfall

इसके साथ, Akka एक अभिनेता ढांचा है जो अभिनेताओं के साथ अधिक उन्नत वर्कफ़्लोज़ के लिए टूल प्रदान करता है, और यही वह है जो मैं किसी भी वास्तविक एप्लिकेशन में उपयोग करता हूं।

import akka.actor.Actor 
import Actor._ 
import akka.routing.{LoadBalancer, CyclicIterator} 

class TaskHandler extends Actor { 
    def receive = { 
    case t: Task => 
     // some computationally expensive thing 
     t.execute 
    case _ => println("default case is required in Akka...") 
    } 
} 

class TaskRouter(numWorkers: Int) extends Actor with LoadBalancer { 
    val workerPool = Vector.fill(numWorkers)(actorOf[TaskHandler].start()) 
    val seq = new CyclicIterator(workerPool) 
} 

val router = actorOf(new TaskRouter(4)).start() 

for(i <- 1 to 20) { 
    router ! Task(..) 
} 

आप लोड संतुलन के विभिन्न प्रकार (CyclicIterator राउंड-रोबिन वितरण है) हो सकता है तो आप अधिक जानकारी के लिए डॉक्स here जाँच कर सकते हैं: यहाँ एक लोड संतुलन कार्य प्रबंधक (बल्कि यादृच्छिक से) है।

2

ठीक है, आप आमतौर पर नहीं करते हैं। अभिनेताओं का उपयोग करने के आकर्षण का एक हिस्सा यह है कि वे आपके लिए ऐसे विवरण संभालते हैं।

अगर, हालांकि, आपको लगता है कि प्रबंध पर जोर देते हैं, तो आप अपने Actor वर्ग पर संरक्षित scheduler विधि ओवरराइड करने के लिए एक उचित IScheduler वापस जाने के लिए की आवश्यकता होगी। scala.actors.scheduler package और शेड्यूलर से संबंधित Actor trait पर टिप्पणियां भी देखें।