Подтвердить что ты не робот

Как использовать бассейн goroutine

Я хочу использовать Go для загрузки электронных таблиц цен в Yahoo. Я сделаю http-запрос для каждого запаса в своем собственном goroutine. У меня есть список около 2500 символов, но вместо того, чтобы делать 2500 запросов параллельно, я бы предпочел делать 250 за раз. В Java я бы создал пул потоков и повторно использовал потоки, когда и когда они освободятся. Я пытался найти что-то подобное, goroutine pool, если хотите, но не смог найти никаких ресурсов. Я был бы признателен, если кто-нибудь скажет мне, как выполнить поставленную задачу или указать мне ресурсы на то же самое. Спасибо!

4b9b3361

Ответ 1

Простейший способ, я полагаю, состоит в том, чтобы создать 250 goroutines и передать им канал, который вы можете использовать для передачи ссылок с главного goroutine на дочерние, прослушивания этого канала.

Когда все ссылки передаются в goroutines, вы закрываете канал, и все goroutines просто заканчивают свои задания.

Чтобы защитить себя от основного goroutine, закончить до того, как дети обработают данные, вы можете использовать sync.WaitGroup.

Вот какой код для иллюстрации (не окончательная рабочая версия, но показывает точку), о которой я сказал выше:

func worker(linkChan chan string, wg *sync.WaitGroup) {
   // Decreasing internal counter for wait-group as soon as goroutine finishes
   defer wg.Done()

   for url := range linkChan {
     // Analyze value and do the job here
   }
}

func main() {
    lCh := make(chan string)
    wg := new(sync.WaitGroup)

    // Adding routines to workgroup and running then
    for i := 0; i < 250; i++ {
        wg.Add(1)
        go worker(lCh, wg)
    }

    // Processing all links by spreading them to `free` goroutines
    for _, link := range yourLinksSlice {
        lCh <- link
    }

    // Closing channel (waiting in goroutines won't continue any more)
    close(lCh)

    // Waiting for all goroutines to finish (otherwise they die as main routine dies)
    wg.Wait()
}

Ответ 2

Вы можете использовать библиотеку реализации пула потоков в Go из этого git repo

Здесь - хороший блог о том, как использовать каналы в качестве пула потоков

Фрагмент из блога

    var (
 MaxWorker = os.Getenv("MAX_WORKERS")
 MaxQueue  = os.Getenv("MAX_QUEUE")
)

//Job represents the job to be run
type Job struct {
    Payload Payload
}

// A buffered channel that we can send work requests on.
var JobQueue chan Job

// Worker represents the worker that executes the job
type Worker struct {
    WorkerPool  chan chan Job
    JobChannel  chan Job
    quit        chan bool
}

func NewWorker(workerPool chan chan Job) Worker {
    return Worker{
        WorkerPool: workerPool,
        JobChannel: make(chan Job),
        quit:       make(chan bool)}
}

// Start method starts the run loop for the worker, listening for a quit channel in
// case we need to stop it
func (w Worker) Start() {
    go func() {
        for {
            // register the current worker into the worker queue.
            w.WorkerPool <- w.JobChannel

            select {
            case job := <-w.JobChannel:
                // we have received a work request.
                if err := job.Payload.UploadToS3(); err != nil {
                    log.Errorf("Error uploading to S3: %s", err.Error())
                }

            case <-w.quit:
                // we have received a signal to stop
                return
            }
        }
    }()
}

// Stop signals the worker to stop listening for work requests.
func (w Worker) Stop() {
    go func() {
        w.quit <- true
    }()
}