go:多任务线程池并发 1

为充分利用多核CPU资源,将原有的单线程执行器改造为并发执行器。任务由单线程产生,根据前批任务的输出决定本次可并发执行的任务数。线程池用于并行计算,通过哈希方式分配任务,但目前未实现任务结果的回调分析,后续将继续优化。

需求来源

原本有一个单线程执行器,用来执行多任务计算,但是单线程执行并没有很好利用系统多核 CPU 资源的优势。于是,需要把执行器改成并发执行的执行器。
首先,有一点需要明确的是,需要的进行计算的多任务并不是一次就抛出来的。这是一个实际中遇到的真实的情况。
任务的来源,是一个单线程的计算结果,至于单线程内部做了什么事情,这里不需要关心,重要的是该单线程的返回结果,如果不抛出异常,有可能可以返回多个可并发执行的任务,也可能一个任务也不会返回,但是下一次在执行单线程,有可能能返回可并发执行任务。
这是因为前面一个批次的某个任务或者某几个任务包含后面任务需要的关键输入参数、如果参数得不到满足、单线程不会将任务抛出。只有当任务需要的关键参数全部满足,单线程才会将任务抛出来。
当任务被单线程抛出之后,需要充分调动多核CPU资源的优势,进行并行计算,同时又要作出限制,不能随便就出现内存溢出这种情况。
所以,构造线程池就成为了解决方案之一。

构造方案

// 定义线程池
type HashSyncWorker struct {
    workerCount uint32
    workers map[uint32]*SyncWorker
}

// 创建 workers 个线程,并给每个线程创建一个 goroutine
// 每个 goroutine 监听一个 channel ,并给channel 设置缓冲区大小为 size 
func NewHashSyncWorker(workers uint32, size int) *HashSyncWorker {
    hashWorker := &HashSyncWorker {
        workerCount: workers,
        workers: make(map[uint32]*SyncWorker),
    }
    var i uint32
    for i = 0; i < workers; i ++ {
        hashWorker.workers[i] = NewSyncWorker(size, 1)
    }

    return hashWorker
}

func _hashStrToInt(s string) uint32 {
    h := fnv.New32a()
    h.Write([]byte(s))
    return h.Sum32()
}

// 将任务以 hash 方式投入线程池
func (syncer *HashSyncWorker)IssueOperation(key string, data interface{}, fn func(interface{})error,
    sync bool, timeout int) error {
    workerIndex := _hashStrToInt(key) % syncer.workerCount

    return syncer.workers[workerIndex].IssueOperation(data, fn, sync, timeout)
}

type syncWorkTask struct {
    fn func(interface{}) error
    data interface{}
    sync bool
    resp chan bool
    err error
}

type SyncWorker struct {
    tasks chan *syncWorkTask
    lock sync.Mutex
}

func NewSyncWorker(size int, workers int) *SyncWorker {
    syncer := &SyncWorker{
        tasks: make(chan *syncWorkTask, size),
        busy: false,
    }

    for i := 0; i < workers; i ++ {
        go func() {
            var task *syncWorkTask = nil
            for {
                task = <- syncer.tasks
                syncer.HandleTask(task)
                task = nil
            }
        }()
    }

    return syncer
}

func (syncer *SyncWorker)IssueOperation(data interface{}, fn func(interface{})error, sync bool, timeout int) error {

    task := &syncWorkTask {
        data: data,
        fn: fn,
        sync: sync,
    }

    if sync {
        task.resp = make(chan bool, 1)
    } else {
        task.resp = nil
    }

    syncer.tasks <- task

    if sync {
        if timeout > 0 {
            select {
            case <- time.After(time.Duration(timeout) * time.Second):
                return errors.New("The sync operation is timeout")
            case <- task.resp:
                return task.err
            }
        } else {
            <- task.resp
            return task.err
        }
    }

    return nil
}

任务投递及结果

采用了线程池,并且任务通过hash 方式向线程池投递,但是,仅仅只是向线程池进行任务投递,而没有进行任务计算结果分析进行回调。只算是完成了高并行运算,持续改进中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值