2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
कोरौटिन् एकः उपयोक्तृस्तरीयः लघुसूत्रः अस्ति यस्य स्वतन्त्रः स्टैक् स्पेसः भवति तथा च प्रोग्रामस्य ढेरस्थानं साझां करोति ।
एतत् एकसूत्रस्य आधारेण एल्गोरिदम्-माध्यमेन कार्यान्वितः सूक्ष्म-सूत्रम् अस्ति बहु-सूत्र-प्रोग्रामिङ्गस्य तुलने अस्य निम्नलिखित-लाभाः सन्ति ।
चैनल् इति एकः दत्तांशसंरचना यस्य उपयोगः कोर्युटिन्-मध्ये संचारार्थं भवति । पङ्क्तिसदृशम् एकः अन्तः प्रेषकः अपरः अन्तः ग्राहकः । चैनल्-उपयोगेन दत्तांशस्य समन्वयनं क्रमं च सुनिश्चितं कर्तुं शक्यते ।
चैनल्स् बफरयुक्तेषु चैनलेषु, अबफरयुक्तेषु चॅनेलेषु च विभक्ताः भवन्ति, ये निम्नलिखितरूपेण घोषिताः भवन्ति ।
intChan := make(chan int,<缓冲容量>)
intChan := make(chan int)
बफर-चैनल-अनबफर-चैनेल्-योः मध्ये अन्तरम् :
अबफर-चैनेल्-कार्यन्वयने यत् ज्ञातव्यं तत् अस्ति यत् चैनल्-उभय-अन्तयोः प्रेषकः ग्राहकश्च भवितुमर्हति, अन्यथा गतिरोधः भविष्यति
प्रश्नस्य अर्थः : क्रमेण 1-10 संख्याः AJ अक्षराणि च मुद्रयितुं coroutine-channel इत्यस्य उपयोगं कुर्वन्तु।
संहिता : १.
- package main
-
- import (
- "fmt"
- "sync"
- )
-
- /*
- 无缓冲chanel:需要在写入chanel的时候要保证有另外一个协程在读取chanel。否则会导致写端阻塞,发生死锁
- 解决办法:
- 避免死锁的发生:
- 当i循环到10时,printAlp协程已然结束,所以此时不必再写入alp通道
- */
-
- func printNum(wg *sync.WaitGroup, numCh chan struct{}, alpCh chan struct{}) {
- defer wg.Done()
-
- for i := 1; i <= 10; i++ {
- <-alpCh // 等待字母goroutine发信号
- fmt.Print(i, " ")
- //避免死锁发生
- if i < 10 {
- numCh <- struct{}{} // 发信号给字母goroutine
- }
- if i == 10 {
- close(numCh)
- }
- }
-
- }
-
- func printAlp(wg *sync.WaitGroup, numCh chan struct{}, alpCh chan struct{}) {
- defer wg.Done()
-
- for i := 'A'; i <= 'J'; i++ {
- <-numCh // 等待数字goroutine发信号
- fmt.Printf("%c", i)
- alpCh <- struct{}{} // 发信号给数字goroutine
- }
- close(alpCh)
- }
-
- func main() {
- numCh := make(chan struct{}) // 用于数字goroutine的信号通道
- alpCh := make(chan struct{}) // 用于字母goroutine的信号通道
- var wg sync.WaitGroup
-
- wg.Add(2)
-
- go printAlp(&wg, numCh, alpCh)
- go printNum(&wg, numCh, alpCh)
-
- // 启动时先给数字goroutine发送一个信号
- numCh <- struct{}{}
-
- wg.Wait()
-
- }
विषयविश्लेषणम् : १.
प्रश्ने अस्माभिः क्रमेण अक्षराणां सङ्ख्यानां च मुद्रणं करणीयम्, अतः अस्माभिः द्वयोः कोर्युटिन्योः कठोरक्रमः सुनिश्चितः करणीयः, यः अबफर-चैनलस्य अनुप्रयोग-परिदृश्येन सह सङ्गतः अस्ति क्रमशः सङ्ख्याः अक्षराणि च संग्रहीतुं द्वौ चॅनेलौ स्थापयन्तु ये क्रमेण सङ्ख्याः अक्षराणि च मुद्रयन्ति। एकवारं लूप् मध्ये मुद्रयन्तु तथा च एकवारं संकेतं प्रेषयन्तु यत् अन्यं कोर्युटिन् मुद्रयितुं स्मरणं कुर्वन्तु ।
ज्ञातव्यं यत् यदा अन्तिमः वर्णः '10' मुद्रितः भवति तदा अक्षराणां मुद्रणार्थं कोरौटिन् समाप्तं भवति, तथा च numCh चैनल् इत्यस्य ग्राहकः नास्ति, अस्मिन् समये, अबफर-चैनलस्य कार्यान्वयन-शर्ताः न पूर्यन्ते - अवश्यमेव सन्ति प्रेषकः ग्राहकश्च अन्यथा पुनः संकेतं प्रेषयित्वा अवरोधन गतिरोधः भविष्यति । अतः पुनः १० वारं संकेतं प्रेषयितुं आवश्यकता नास्ति।
शीर्षकम्: एकं कार्यनिर्मातारं डिजाइनं कुर्वन्तु यत् बहु-कार्यस्य समवर्ती-प्रक्रियाकरणस्य व्यावसायिक-परिदृश्यानां कार्यान्वयनार्थं बहु-कोरोटीन + चैनल-प्रोग्रामिंग-प्रतिरूपस्य उपयोगं करोति, तथा च समयनिर्धारण-क्रमस्य आवश्यकता यस्मिन् क्रमे कार्याणि योजिताः भवन्ति तस्मिन् क्रमे भवितुं आवश्यकम्
संहिता : १.
- type scheduler struct {
- taskChan chan func()
- wt sync.WaitGroup
- }
-
- func (td *scheduler) AddTask(task func()) {
- td.taskChan <- task
- }
-
- func (td *scheduler) Executer() {
- defer td.wt.Done()
- for {
- task, ok := <-td.taskChan
- task()
- if ok && len(td.taskChan) == 0 {
- break
- }
- }
- }
-
- func (td *scheduler) Start() {
- td.wt.Add(4)
- //假设四个消费者
- for i := 0; i < 4; i++ {
- go td.Executer()
- }
-
- td.wt.Wait()
- }
-
- func main() {
- sd := scheduler{
- taskChan: make(chan func(), 5),
- }
-
- go func() {
- sd.AddTask(func() {
- fmt.Println("任务1")
- })
- sd.AddTask(func() {
- fmt.Println("任务2")
- })
- sd.AddTask(func() {
- fmt.Println("任务3")
- })
- sd.AddTask(func() {
- fmt.Println("任务4")
- })
- sd.AddTask(func() {
- fmt.Println("任务5")
- })
- sd.AddTask(func() {
- fmt.Println("任务6")
- })
- close(sd.taskChan)
- }()
-
- sd.Start()
-
- }
समस्याविश्लेषणम् : १.
यतो हि योजितकार्यं बहुकार्यं भवति, तस्मात् एकादशाधिकं भवति, एतानि कार्याणि निष्पादयितुं अतुल्यकालिकप्रक्रिया आवश्यकी भवति । बफर-चैनलस्य अनुपालनाय उन्नत-थ्रूपुट्-अतुल्यकालिक-प्रक्रियाकरणस्य आवश्यकता भवति ।
ततः, अस्माभिः कार्यं चैनल् मध्ये स्थापयितुं आवश्यकम्, तथा च बहुविधाः ग्राहकाः चैनल् तः कार्याणि क्रमेण गृहीत्वा निष्पादयितुं शक्नुवन्ति ।
समस्या यस्याः ध्यानस्य आवश्यकता वर्तते सा अस्ति यत् यदि योजितानां कार्याणां संख्या चैनलस्य बफरात् अधिका भवति तर्हि कार्याणि योजयित्वा अवरोधं जनयिष्यति । उपभोक्तुः सामान्यप्रारम्भं न प्रभावितं कर्तुं कार्याणि योजयितुं पृथक् कोरूटिन् उद्घाटयितुं आवश्यकम् ।
एवं प्रकारेण यदा उपभोक्ता उपभोगं करोति तदा अवरोधकः उत्पादकः कार्याणि निरन्तरं योजयितुं जागरितः भविष्यति ।
coroutine + channel programming model इत्यस्य अध्ययनानन्तरं शीर्षके एव यत् उक्तं तस्य अतिरिक्तं अस्माभिः निम्नलिखितविषयेषु अपि ध्यानं दातव्यम् ।
प्रथमं तु मार्गस्य बन्दीकरणस्य मूलभूततमः सिद्धान्तः अस्ति यत् ये मार्गाः बन्दाः सन्ति तेषां बन्दीकरणं न करणीयम् । द्वितीयं, Go चैनल् इत्यस्य उपयोगाय अन्यः सिद्धान्तः अस्ति :दत्तांशग्राहके वा यदा बहुविधप्रेषकाः सन्ति तदा वा चैनलं न पिधायन्तु।अन्येषु शब्देषु,अस्माभिः केवलं कस्यचित् चैनलस्य एकमात्रं प्रेषकं एतत् चैनलं बन्दं कर्तुं अर्हति।
एकः अशिष्टः उपायः अपवादपुनर्प्राप्तिद्वारा चैनलं बन्दं कर्तुं भवति, परन्तु एतत् स्पष्टतया उपर्युक्तसिद्धान्तानां उल्लङ्घनं करोति तथा च अन्यः उपायः अस्ति यत् sync.Once अथवा sync.Mutex इत्यनेन चैनलं बन्दं करणीयम्, यत् Concurrent close इति भवितुं गारण्टी नास्ति एकस्मिन् चैनले ऑपरेशन्स् तथा सेण्ड् ऑपरेशन्स् च दत्तांशदौडं न निर्मान्ति । उभयोः पद्धतयोः कतिपयानि समस्यानि सन्ति, अतः अहं तान् विस्तरेण न परिचययिष्यामि ।
निवारणार्थं सुलभतमासु परिस्थितिषु अन्यतमा। यदा प्रेषकस्य प्रेषणं समाप्तं कर्तव्यं भवति तदा केवलं तत् चैनलं पिधातु । उपरिष्टात् प्रोग्रामिंग् उदाहरणद्वये एतत् ।
Go channels इत्यस्य मूलभूतसिद्धान्तानुसारं वयं केवलं चैनलस्य एकमात्रप्रेषकस्थाने एव चैनलं पिधातुं शक्नुमः । अतः, अस्मिन् सन्दर्भे वयं प्रत्यक्षतया कुत्रचित् चैनलं पिधातुं न शक्नुमः ।परन्तु वयं ग्राहकं अतिरिक्तं संकेतमार्गं बन्दं कर्तुं शक्नुमः यत् प्रेषकं अधिकं दत्तांशं न प्रेषयितुं वक्तुं शक्नोति।。
- package main
-
- import (
- "log"
- "sync"
- )
-
- func main() {
-
- cosnt N := 5
- cosnt Max := 60000
- count := 0
-
- dataCh := make(chan int)
- stopCh := make(chan bool)
-
- var wt sync.WaitGroup
- wt.Add(1)
-
- //发送者
- for i := 0; i < N; i++ {
- go func() {
- for {
- select {
- case <-stopCh:
- return
- default:
- count += 1
- dataCh <- count
- }
- }
- }()
- }
-
- //接收者
- go func() {
- defer wt.Done()
- for value := range dataCh {
- if value == Max {
- // 此唯一的接收者同时也是stopCh通道的
- // 唯一发送者。尽管它不能安全地关闭dataCh数
- // 据通道,但它可以安全地关闭stopCh通道。
- close(stopCh)
- return
- }
- log.Println(value)
- }
- }()
-
- wt.Wait()
- }
अस्मिन् पद्धत्या वयं अतिरिक्तं सिग्नल् चैनल् stopCh योजयामः, यस्य उपयोगेन ग्राहकः प्रेषकं कथयति यत् तस्य दत्तांशस्य प्राप्तेः आवश्यकता नास्ति इति । अपि च, एषा पद्धतिः dataCh न बन्दं करोति यदा कश्चन चैनलः कस्यापि कोरटीनेन न पुनः उपयुज्यते तदा सः क्रमेण कचरासंगृहीतः भविष्यति, यद्यपि सः बन्दः अस्ति वा।
अस्य पद्धतेः सौन्दर्यं अस्ति यत् एकं चैनलं पिधाय अन्यस्य चैनलस्य उपयोगं त्यजति, तस्मात् अन्यं चैनलं परोक्षरूपेण पिधायति ।
वयं ग्राहकं प्रेषकं वा दत्तांशसञ्चारार्थं प्रयुक्तं मार्गं बन्दं कर्तुं न शक्नुमः, न च बहुग्राहिषु एकं अतिरिक्तं संकेतमार्गं बन्दं कर्तुं शक्नुमः एतयोः द्वयोः अपि अभ्यासयोः चैनल् बन्दीकरणसिद्धान्तस्य उल्लङ्घनं भवति ।
तथापि वयं परिचयं कर्तुं शक्नुमःएकः मध्यवर्ती मध्यस्थभूमिका तथा च कार्यस्य समाप्तेः सर्वेभ्यः ग्राहकेभ्यः प्रेषकेभ्यः च सूचयितुं अतिरिक्तसंकेतमार्गान् बन्दं कृत्वा。
कोड उदाहरणम् : १.
- package main
-
- import (
- "log"
- "math/rand"
- "strconv"
- "sync"
- )
-
- func main() {
-
- const Max = 100000
- const NumReceivers = 10
- const NumSenders = 1000
-
- var wt sync.WaitGroup
- wt.Add(NumReceivers)
-
- dataCh := make(chan int)
- stopCh := make(chan struct{})
- // stopCh是一个额外的信号通道。它的发送
- // 者为中间调解者。它的接收者为dataCh
- // 数据通道的所有的发送者和接收者。
- toStop := make(chan string, 1)
- // toStop是一个用来通知中间调解者让其
- // 关闭信号通道stopCh的第二个信号通道。
- // 此第二个信号通道的发送者为dataCh数据
- // 通道的所有的发送者和接收者,它的接收者
- // 为中间调解者。它必须为一个缓冲通道。
-
- var stoppedBy string
-
- // 中间调解者
- go func() {
- stoppedBy = <-toStop
- close(stopCh)
- }()
-
- // 发送者
- for i := 0; i < NumSenders; i++ {
- go func(id string) {
- for {
- value := rand.Intn(Max)
- if value == 0 {
- // 为了防止阻塞,这里使用了一个尝试
- // 发送操作来向中间调解者发送信号。
- select {
- case toStop <- "发送者#" + id:
- default:
- }
- return
- }
-
- select {
- case <-stopCh:
- return
- case dataCh <- value:
- }
- }
- }(strconv.Itoa(i))
- }
-
- // 接收者
- for i := 0; i < NumReceivers; i++ {
- go func(id string) {
- defer wt.Done()
-
- for {
- select {
- case <-stopCh:
- return
- case value := <-dataCh:
- if value == Max {
- // 为了防止阻塞,这里使用了一个尝试
- // 发送操作来向中间调解者发送信号。
- select {
- case toStop <- "接收者:" + id:
- default:
- }
- return
- }
-
- log.Println(value)
- }
- }
- }(strconv.Itoa(i))
- }
-
- wt.Wait()
- log.Println("被" + stoppedBy + "终止了")
-
- }