Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 合并通道中的项目_Multithreading_Go_Queue - Fatal编程技术网

Multithreading 合并通道中的项目

Multithreading 合并通道中的项目,multithreading,go,queue,Multithreading,Go,Queue,我有一个函数,它接收任务并将它们放入通道中。每个任务都有ID、一些属性和一个放置结果的通道。看起来像这样 task.Result = make(chan *TaskResult) queue <- task result := <-task.Result sendReponse(result) 所以,我可以使用go channel和map for random access+一些同步手段(如互斥)来实现它。我不喜欢这种方式,因为我必须在代码中同时携带map和channel,并保持它

我有一个函数,它接收任务并将它们放入通道中。每个任务都有ID、一些属性和一个放置结果的通道。看起来像这样

task.Result = make(chan *TaskResult)
queue <- task
result := <-task.Result
sendReponse(result)
所以,我可以使用go channel和map for random access+一些同步手段(如互斥)来实现它。我不喜欢这种方式,因为我必须在代码中同时携带map和channel,并保持它们的内容同步

第二种方法是将所有任务放入队列,但在结果到达时从队列中提取任务和具有相同ID的所有任务,然后将结果发送给所有任务。这是伪代码

if newTask in queue {
  existing := queue.getById(newTask.ID)
  existing.waitForComplete()
  sendResponse(existing.ProcessingResult)
} else {
  queue.enqueue(newTask)
}
someTask := queue.dequeue()
result := doExpensiveComputation(someTask)
someTask.Result <- result
moreTasks := queue.getAllWithID(someTask.ID)
for _,theSameTask := range moreTasks {
  theSameTask.Result <- result
}
someTask:=queue.dequeue()
结果:=doExpensiveComputation(someTask)

someTask.Result如果我正确理解了这个问题,我想到的最简单的解决方案就是在任务发送者(放入
队列
)和工作者(取自
队列
)之间添加一个中间层。这可能是一个例行程序,负责存储当前任务(按ID),并将结果广播给每个匹配的任务

伪密码:

go func() {
    active := make(map[TaskID][]Task)

    for {
        select {
        case task := <-queue:
            tasks := active[task.ID]
            // No tasks with such ID, start heavy work
            if len(tasks) == 0 {
                worker <- task
            }
            // Save task for the result
            active[task.ID] = append(active[task.ID], task)
        case r := <-response:
            // Broadcast to all tasks
            for _, task := range active[r.ID] {
                task.Result <- r.Result
            }
        }
    }
}()

如果您只想使用唯一ID处理每个任务一次,那么为什么不在发送端检查唯一性呢?也就是说,
if u,sent:=alreadySentIDs[ID]!发送{queue@Ainar-G我也想获得处理结果,因此您的代码应该有其他branchHappy来帮助。我不知道您的流到底是什么样子,但我意识到,使用这样一个简单的示例,您很容易陷入死锁。我编辑了我的答案,以便进一步讨论这个问题。
go func() {
    active := make(map[TaskID][]Task)

    for {
        select {
        case task := <-queue:
            tasks := active[task.ID]
            // No tasks with such ID, start heavy work
            if len(tasks) == 0 {
                worker <- task
            }
            // Save task for the result
            active[task.ID] = append(active[task.ID], task)
        case r := <-response:
            // Broadcast to all tasks
            for _, task := range active[r.ID] {
                task.Result <- r.Result
            }
        }
    }
}()
go func() {
    var next Task // received task which needs to be passed to a worker
    in := queue // incoming channel (new tasks) -- active
    var out chan Task // outgoing channel (to workers) -- inactive
    for {
        select {
        case t := <-in:
            next = t // store task, so we can pass to worker
            in, out = nil, worker // deactivate incoming channel, activate outgoing
        case out <- next:
            in, out = queue, nil // deactivate outgoing channel, activate incoming
        case r := <-response:
            collect <- r
        }
    }
}()