কীভাবে গোরোটিন বন্ধ করতে হয়


107

আমার কাছে একটি গোরোটিন রয়েছে যা একটি পদ্ধতি কল করে এবং একটি চ্যানেলে প্রত্যাবর্তিত মানটি দেয়:

ch := make(chan int, 100)
go func(){
    for {
        ch <- do_stuff()
    }
}()

আমি কীভাবে এমন গোরোটিন বন্ধ করব?


4
আপনার পরিস্থিতির উপর নির্ভর করে আরেকটি উত্তর হ'ল গো প্রসঙ্গ ব্যবহার করা। এ সম্পর্কে একটি উত্তর তৈরি করার মতো সময় বা জ্ঞান আমার নেই। আমি কেবল এটি এখানে উল্লেখ করতে চেয়েছিলাম যাতে এই উত্তরটি অসন্তুষ্ট হওয়া লোকেরা অনুসন্ধান করে এবং খুঁজে পেতে পারে তাদের কাছে টানতে আরও একটি থ্রেড রয়েছে (পাং উদ্দেশ্যে)। বেশিরভাগ ক্ষেত্রে, আপনার গ্রহণযোগ্য উত্তর হিসাবে পরামর্শ দেওয়া উচিত। এই উত্তরটি প্রেক্ষিতে উল্লেখ: stackoverflow.com/a/47302930/167958
সর্ববিধ

উত্তর:


53

সম্পাদনা: আমি এই উত্তরটি তড়িঘড়ি করে লিখেছিলাম, বুঝতে পারার আগে যে আপনার প্রশ্নটি গোরোটিনের অভ্যন্তরে কোনও চ্যানে মান পাঠানো। উপরে প্রস্তাবিত হিসাবে অতিরিক্ত চ্যানের সাহায্যে নীচের পদ্ধতিটি ব্যবহার করা যেতে পারে, বা আপনার ইতিমধ্যে যে চ্যানটি দ্বি-দিকনির্দেশক তা ব্যবহার করে আপনি কেবলমাত্র একটিটি ব্যবহার করতে পারেন ...

যদি আপনার গুরোটাইন কেবল চ্যান থেকে বেরিয়ে আসা আইটেমগুলি প্রক্রিয়া করার জন্য বিদ্যমান থাকে তবে আপনি "বন্ধ" বিল্টিন এবং চ্যানেলগুলির জন্য বিশেষ প্রাপ্ত ফর্মটি ব্যবহার করতে পারেন।

এটি হ'ল একবার চ্যানে আইটেম পাঠানো শেষ হয়ে গেলে আপনি এটি বন্ধ করে দিন। তারপরে আপনার গোরোটিনের অভ্যন্তরে আপনি রিসিভ অপারেটরের একটি অতিরিক্ত প্যারামিটার পাবেন যা চ্যানেলটি বন্ধ হয়েছে কিনা তা দেখায়।

এখানে একটি সম্পূর্ণ উদাহরণ রয়েছে (গুরোটিন সম্পূর্ণ না হওয়া পর্যন্ত প্রক্রিয়াটি অব্যাহত থাকে তা নিশ্চিত করার জন্য ওয়েটগ্রুপ ব্যবহার করা হয়):

package main

import "sync"
func main() {
    var wg sync.WaitGroup
    wg.Add(1)

    ch := make(chan int)
    go func() {
        for {
            foo, ok := <- ch
            if !ok {
                println("done")
                wg.Done()
                return
            }
            println(foo)
        }
    }()
    ch <- 1
    ch <- 2
    ch <- 3
    close(ch)

    wg.Wait()
}

17
চ্যানেলটি বন্ধ না হওয়া পর্যন্ত অভ্যন্তরীণ গোরোটিনের দেহটি অধিকতর আইডেমিক্যালি লিখিত deferহয় wg.Done()এবং range chচ্যানেলটি বন্ধ না হওয়া পর্যন্ত সমস্ত মানকে পুনরুক্ত করে lo
অ্যালান ডোনভান

120

সাধারণত, আপনি জোরোটাইন একটি (সম্ভবত পৃথক) সংকেত চ্যানেলটি পাস করেন। আপনি যখন গোরোটিন থামাতে চান সেই সংকেত চ্যানেলটি কোনও মানকে ঠেলে দিতে ব্যবহৃত হয়। নিয়মিতভাবে চ্যানেলটি জোরোটাইন পোল করে। এটি একটি সংকেত সনাক্ত করার সাথে সাথে এটি প্রস্থান করে।

quit := make(chan bool)
go func() {
    for {
        select {
        case <- quit:
            return
        default:
            // Do other stuff
        }
    }
}()

// Do stuff

// Quit goroutine
quit <- true

26
যথেষ্ট ভাল না. গুরোটিন কোনও বাগের কারণে অন্তহীন লুপে আটকে থাকলে কী হবে?
এলাজার লাইবোভিচ

241
তারপরে বাগটি ঠিক করা উচিত।
জিমট

13
এলাজার, আপনি যা পরামর্শ দিচ্ছেন তা হ'ল কোনও ফাংশন বলার পরে বন্ধ করার উপায়। গোরোটিন কোনও থ্রেড নয়। এটি অন্য কোনও থ্রেডে চলতে পারে বা এটি আপনার মতো একই থ্রেডে চলতে পারে। আমি এমন কোনও ভাষা জানি যা যা আপনাকে যা সমর্থন করে বলে মনে হয় তাকে সমর্থন করে না।
জেরেমি ওয়াল

5
@ জেরেমি গো-এর পক্ষে দ্বিমত পোষণ করছেন না, তবে এরলং আপনাকে এমন একটি প্রক্রিয়া মারার অনুমতি দেয় যা একটি লুপিং ফাংশন চলছে।
ম্যাথিউডডয়ে

11
গো মাল্টিটাস্কিং প্রিপ্রিমটিভ নয়, সমবায়। একটি লুপের একটি জোরোটিন কখনই শিডিয়ুলারে প্রবেশ করে না, তাই এটি কখনও হত্যা করা যায় না।
জেফ অ্যালেন

35

আপনি বাইরে থেকে গোরোটিন মারতে পারবেন না। আপনি কোনও চ্যানেল ব্যবহার বন্ধ করতে গোরোটিনকে সিগন্যাল করতে পারেন, তবে কোনও ধরণের মেটা পরিচালনা করার জন্য গোরোটিনগুলিতে কোনও হ্যান্ডেল নেই। গোরআটাইনগুলি সহযোগিতামূলকভাবে সমস্যাগুলি সমাধান করার উদ্দেশ্যে করা হয়েছে, সুতরাং দুর্ব্যবহারকারীকে হত্যা করা প্রায়শই পর্যাপ্ত প্রতিক্রিয়া হতে পারে না। আপনি যদি দৃ rob়তার জন্য বিচ্ছিন্নতা চান তবে আপনি সম্ভবত একটি প্রক্রিয়া চান।


এবং আপনি এনকোডিং / গব প্যাকেজটি সন্ধান করতে চাইতে পারেন, যা দুটি গো প্রোগ্রামগুলিকে কোনও পাইপের মাধ্যমে সহজেই ডেটা স্ট্রাকচারের আদান-প্রদান করতে দেয়।
জেফ অ্যালেন

আমার ক্ষেত্রে, আমার কাছে একটি গোরআটিন রয়েছে যা একটি সিস্টেম কলে অবরুদ্ধ হবে এবং সিস্টেম কলটি বাতিল করতে এবং তারপরে প্রস্থান করার জন্য আমার এটি বলা দরকার। যদি আমাকে কোনও চ্যানেল পড়তে বাধা দেওয়া হয়, তবে আপনার পরামর্শ অনুসারে এটি করা সম্ভব হবে।
সর্বময়

আমি আগে এই সমস্যাটি দেখেছি। যেভাবে আমরা "সমাধান" করেছি এটি ছিল অ্যাপ্লিকেশন শুরুতে থ্রেডগুলির সংখ্যা বাড়ানো যা গোরআটাইনগুলির সংখ্যার সাথে মিলিত হতে পারে যেগুলি সম্ভবত সিপিইউ'র সংখ্যার সাথে মিলিত হতে পারে
রাউজিয়ার

23

সাধারণত, আপনি একটি চ্যানেল তৈরি করতে এবং গোরোটিনে স্টপ সিগন্যাল পেতে পারেন।

এই উদাহরণে চ্যানেল তৈরির দুটি উপায়।

  1. চ্যানেল

  2. প্রসঙ্গ । উদাহরণে আমি ডেমো করব willcontext.WithCancel

প্রথম ডেমো, ব্যবহার করুন channel:

package main

import "fmt"
import "time"

func do_stuff() int {
    return 1
}

func main() {

    ch := make(chan int, 100)
    done := make(chan struct{})
    go func() {
        for {
            select {
            case ch <- do_stuff():
            case <-done:
                close(ch)
                return
            }
            time.Sleep(100 * time.Millisecond)
        }
    }()

    go func() {
        time.Sleep(3 * time.Second)
        done <- struct{}{}
    }()

    for i := range ch {
        fmt.Println("receive value: ", i)
    }

    fmt.Println("finish")
}

দ্বিতীয় ডেমো, ব্যবহার করুন context:

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    forever := make(chan struct{})
    ctx, cancel := context.WithCancel(context.Background())

    go func(ctx context.Context) {
        for {
            select {
            case <-ctx.Done():  // if cancel() execute
                forever <- struct{}{}
                return
            default:
                fmt.Println("for loop")
            }

            time.Sleep(500 * time.Millisecond)
        }
    }(ctx)

    go func() {
        time.Sleep(3 * time.Second)
        cancel()
    }()

    <-forever
    fmt.Println("finish")
}

12

আমি জানি এই উত্তরটি ইতিমধ্যে গ্রহণ করা হয়েছে, তবে আমি ভেবেছিলাম আমার 2 টি ছোঁড়া ভিতরে ফেলে দেব I আমি সমাধি প্যাকেজটি ব্যবহার করতে পছন্দ করি । এটি মূলত একটি উত্সাহিত ছাড়ার চ্যানেল, তবে এটি কোনও ত্রুটিও ফিরে দেওয়ার মতো দুর্দান্ত কাজ করে। নিয়ন্ত্রণাধীন রুটিনটিতে এখনও রিমোট কিল সিগন্যালগুলির জন্য চেক করার দায়িত্ব রয়েছে। আফাইক কোনও গোরোটিনের "আইডি" পাওয়া এবং এটি খারাপ ব্যবহার করে (যেমন: অসীম লুপে আটকে) থাকলে এটি হত্যা করা সম্ভব নয়।

এখানে আমি একটি সাধারণ উদাহরণ যা পরীক্ষা করেছি:

package main

import (
  "launchpad.net/tomb"
  "time"
  "fmt"
)

type Proc struct {
  Tomb tomb.Tomb
}

func (proc *Proc) Exec() {
  defer proc.Tomb.Done() // Must call only once
  for {
    select {
    case <-proc.Tomb.Dying():
      return
    default:
      time.Sleep(300 * time.Millisecond)
      fmt.Println("Loop the loop")
    }
  }
}

func main() {
  proc := &Proc{}
  go proc.Exec()
  time.Sleep(1 * time.Second)
  proc.Tomb.Kill(fmt.Errorf("Death from above"))
  err := proc.Tomb.Wait() // Will return the error that killed the proc
  fmt.Println(err)
}

ফলাফলটি দেখতে হবে:

# Loop the loop
# Loop the loop
# Loop the loop
# Loop the loop
# Death from above

এই প্যাকেজটি বেশ আকর্ষণীয়! tombউদাহরণস্বরূপ, আতঙ্ক ছুঁড়ে এমন কিছু ঘটলে যদি গোরোটিনের সাথে কী ঘটে তা আপনি পরীক্ষা করে দেখেছেন ? টেকনিক্যালি এই ক্ষেত্রে হবে ভাষী, goroutine প্রস্থানের, তাই আমি অভিমানী করছি এটি এখনও পিছিয়ে কল proc.Tomb.Done()...
Gwyneth Llewelyn

4
হাই গুইনেথ, হ্যাঁ proc.Tomb.Done()প্যানিকটি প্রোগ্রামটি ক্র্যাশ হওয়ার আগেই সম্পাদন করবে, তবে কি শেষ? এটি সম্ভব যে মূল গোরোটিনের কাছে কিছু বিবৃতি কার্যকর করার খুব সামান্য একটি উইন্ডো থাকতে পারে , তবে এটি অন্য গোরোটিনে আতঙ্ক থেকে পুনরুদ্ধারের কোনও উপায় নেই, সুতরাং প্রোগ্রামটি এখনও ক্র্যাশ করে। ডকস বলেছেন: "ফাংশন এফ আতঙ্কের ডাক দেয়, এফের এক্সিকিউশন বন্ধ হয়ে যায়, এফের যে কোনও স্থগিত ফাংশন স্বাভাবিকভাবে কার্যকর করা হয় এবং তারপরে এফ তার কলারে ফিরে আসে the বর্তমান গরোটিনের সমস্ত ফাংশন ফিরে না আসা পর্যন্ত প্রক্রিয়াটি স্ট্যাক অব্যাহত রাখে, যে মুহুর্তে প্রোগ্রামটি ক্র্যাশ হয়ে গেছে ""
কেভিন ক্যান্টওয়েল

এটি একটি দুর্দান্ত উত্তর - কিছু ক্ষেত্রে প্রসঙ্গ ব্যবহারের চেয়ে ভাল । এপিআইটি এখানে সমাধি.ভি 2 এর সাথে কিছুটা আলাদা তবে একই রকম ব্যবহার ।
অনিরুদ রামানাথন

7

ব্যক্তিগতভাবে, আমি গুরোটিনের একটি চ্যানেলে রেঞ্জটি ব্যবহার করতে চাই:

https://play.golang.org/p/qt48vvDu8cd

ডেভ এই সম্পর্কে একটি দুর্দান্ত পোস্ট লিখেছেন: http://dave.cheney.net/2013/04/30/curious-channels


4
এটা সত্যিই সুন্দর।
প্রোফ্যাশটচ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.