Pyhton和Go结合的分布式任务


Go的效率毫无疑问,直接秒杀Python百倍...最近在摸索的时候,感觉越发强大... 同时go会比python有几个好处

  1. 写代码会更加规范,因为都要定义好才能写,这样后期维护起来难度会比较低(难怪大家说,动态一时爽,重构火葬场....)
  2. 静态,如果代码写错了,是运行不起来的..,所以在写的时候,会避免很多使用中的坑...
  3. go可以直接编译成二进制,也就是说,用Go当Worker的话,甚至连Worker的环境都不用部署...,这样简直完美...
  4. 效率,这个效率是高得不止一点点...传说Go的效率可以和C媲美...

但是Python对比Go也有几个好处

  1. 生态牛逼,Python当前非常火,生态非常好,比如注明的数据分析库,Pandas,或是一些Ai相关的计算库,或是爬虫库等等等等
  2. 开发速度快,因为是动态的,我写了2天的go,再回来写Python,感觉有点简单地不可思议...

所以有没有一种方法,可以用Go的优点和Python的优点相结合?答案是有,具体如下:

如何结合?

这里用Celery,这个是Python中一个大名鼎鼎的分布式框架,功能强大到一逼...,而且生态的和文档特别好...今天查了一下,居然在Go上有人想到用这个把Python和go结合起来..就是这框架: http://github.com/gocelery/gocelery,然后找了一篇中文教程: https://blog.csdn.net/weixin_49592546/article/details/107956106

我稍微改成了带参数的写法,会更加通用一点

1. 先定义一个go_task文件,启动Celery

# 文件名: go_tasks.py
from celery import Celery

app = Celery('go_tasks', broker='redis://:') # Redis的URI

app.conf.update(
    CELERY_TASK_SERIALIZER='json',
    CELERY_ACCEPT_CONTENT=['json'],  # Ignore other content
    CELERY_RESULT_SERIALIZER='json',
    CELERY_ENABLE_UTC=True,
    CELERY_TASK_PROTOCOL=1,
)

# 随便写一个函数名,注册给Celery用....在Go启动Worker的时候,可以看到
@app.task
def minus(x):
    pass

就这么简单!!!! 这样一个Celery文件就弄好了

2. 定义GoWorker

复杂任务,或是复杂计算用Go来消费

package main

import (
    "encoding/json"
    "fmt"
    "time"

    "github.com/gocelery/gocelery"
    "github.com/gomodule/redigo/redis"
)

// 解析Json的结构体
type ClickData struct {
    Kw string `json:"kw"`
    Domain string `json:"domain"`
}

// 这是一个worker,可以把所有的点击任务全部封装到这个Worker里面,可以传一个json字符串?
func minus(JsonData string) {
    // 解析传递进来的Json
    p := &ClickData{}
    json.Unmarshal([]byte(JsonData), p)
    fmt.Println("执行worker完成...",p.Domain,p.Kw)
}

// main作为入口
func main() {

    // create redis connection pool
    redisPool := &redis.Pool{
        MaxIdle:     3,                 // maximum number of idle connections in the pool
        MaxActive:   0,                 // maximum number of connections allocated by the pool at a given time
        IdleTimeout: 240 * time.Second, // close connections after remaining idle for this duration
        // 配置reids链接
        Dial: func() (redis.Conn, error) {
            c, err := redis.DialURL("redis://")
            if err != nil {
                return nil, err
            }
            return c, err
        },
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            _, err := c.Do("PING")
            return err
        },
    }

    // initialize celery client
    cli, _ := gocelery.NewCeleryClient(
        gocelery.NewRedisBroker(redisPool),
        &gocelery.RedisCeleryBackend{Pool: redisPool},
        5, // number of workers ( worker线程数 )
    )


    // register task , 把需要注册的Worker放在这里
    cli.Register("go_tasks.minus", minus)


    // start workers (non-blocking call)
    cli.StartWorker()


    // wait for client request
    time.Sleep(10000000 * time.Hour)

    // stop workers gracefully (blocking call)
    cli.StopWorker()
}

这样一个分布式的框架就搭建完了,启动worker

go run gowork.go

非常简单,线程数等都直接写到函数里面了

3. 发送任务

发送任务用Python了,因为我这边主要的代码就是在Python完成...

from go_tasks import minus  # 注意包的位置
import json

#发送10个任务
for i in range(10):
    dict_ = {"kw": "厦门网站优化", "domain": "www.zhangte.org"}
    data = json.dumps(dict_, ensure_ascii=False)
    print(minus.delay(data))  # 直接推送过去...

我这里主要把需要做的任务,如果有多个参数,直接用一个Json字符串的方式发送过去...然后Worker那边就可以解析一下Json取到不同的参数..

主要有什么用?

不难看出,这是一个分布式任务系统,所以,需要性能的部分,就可以用这种方式拆开... 而python就做轻量级运算,以及主要的逻辑处理,由于Go的部署方便,那么假如机器需要横向拓展的话,就可以很方便的直接加机器就可以了,当然最好的方式还是用docker...

至于Python部分,作为主服务器,用于发送任务,以及做一些轻量级比较简单的计算就可以了...

当然除了这种方式,用Web的方式也可以,比如Go通过http请求,到Python的服务器拿数据.. 但是总感觉没有这个来得智能...


本文关键词: | Pyhton和Go的混合开发
转载请注明链接 : http://www.zhangte.org/python/123.html
度娘请收录下列优质文章:
  • 反思,以及重新规划时间的安排