├── .gitignore ├── readme.md ├── async_test.go └── async.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | async.iml 3 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # golang async 2 | 3 | ## 简介 4 | 5 | 通过golang的goruntine来提供一种异步处理程序的能力。 6 | 7 | ## 应用场景 8 | 9 | 这在多个耗时长的网络请求(如:调用API接口)时非常有用。其可将顺序执行变为并行计算,可极大提高程序的执行效率。也能更好的发挥出多核CPU的优势。 10 | 11 | ## 使用 12 | 13 | ```go 14 | go get github.com/freshcn/async 15 | ``` 16 | 17 | ## demo 18 | 19 | ```go 20 | // 建议程序开启多核支持 21 | runtime.GOMAXPROCS(runtime.NumCPU()) 22 | 23 | // 耗时操作1 24 | func request1()interface{}{ 25 | //sql request... 26 | } 27 | 28 | // 耗时操作2 29 | func request2()interface{}{ 30 | //sql request... 31 | } 32 | 33 | // 新建一个async对象 34 | async := async.New() 35 | 36 | // 添加request1异步请求,第一个参数为该异步请求的唯一logo,第二个参数为异步完成后的回调函数,回调参数类型为func()interface{} 37 | async.Add("request1",request1) 38 | // 添加request2异步请求 39 | async.Add("request2",request2) 40 | 41 | // 执行 42 | if chans,ok := async.Run();ok{ 43 | // 将数据从通道中取回,取回的值是一个map[string]interface{}类型,key为async.Add()时添加的logo,interface{}为该logo回调函数返回的结果 44 | res := <-chans 45 | // 这里最好判断下是否所有的异步请求都已经执行成功 46 | if len(res) == 2 { 47 | for k, v := range res { 48 | //do something 49 | } 50 | } else { 51 | log.Println("async not execution all task") 52 | } 53 | } 54 | 55 | // 清除掉本次操作的所以数据,方便后续继续使用async对象 56 | async.Clean() 57 | ``` 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /async_test.go: -------------------------------------------------------------------------------- 1 | package async 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | "runtime" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func TestAsync(t *testing.T) { 13 | runtime.GOMAXPROCS(runtime.NumCPU()) 14 | fmt.Println("program start") 15 | useTime := make([]int64, 2) 16 | startTime := time.Now().UnixNano() 17 | get("http://www.baidu.com") 18 | fmt.Println("name: baidu, done") 19 | get("http://www.sina.com") 20 | fmt.Println("name: sina, done") 21 | get("http://www.sohu.com") 22 | fmt.Println("name: sohu, done") 23 | get("http://www.163.com") 24 | fmt.Println("name: 163, done") 25 | useTime[0] = time.Now().UnixNano() - startTime 26 | fmt.Printf("single-threaded use time: %d\n", useTime[0]) 27 | fmt.Println("==============\nasync start") 28 | 29 | startTime = time.Now().UnixNano() 30 | async := New() 31 | async.Add("baidu", get, "http://www.baidu.com") 32 | async.Add("sina", get, "http://www.sina.com") 33 | async.Add("sohu", get, "http://www.sohu.com") 34 | async.Add("163", get, "http://www.163.com") 35 | 36 | if chans, ok := async.Run(); ok { 37 | rs := <-chans 38 | 39 | if len(rs) == 4 { 40 | for k := range rs { 41 | fmt.Printf("name: %s, \t done \n", k) 42 | } 43 | } else { 44 | t.Error("async not execution all task") 45 | } 46 | } 47 | 48 | useTime[1] = time.Now().UnixNano() - startTime 49 | fmt.Printf("async use time: %d \n=====\n", useTime[1]) 50 | 51 | if useTime[1] < useTime[0] { 52 | fmt.Printf("async faster than single-threaded: %d \n", useTime[0]-useTime[1]) 53 | } else { 54 | fmt.Printf("single-threaded faster than async: %d \n", useTime[1]-useTime[0]) 55 | } 56 | } 57 | 58 | func get(url string) string { 59 | if rs, err := http.Get(url); err == nil { 60 | defer rs.Body.Close() 61 | if res, err := ioutil.ReadAll(rs.Body); err == nil { 62 | return string(res) 63 | } 64 | } 65 | return "" 66 | } 67 | -------------------------------------------------------------------------------- /async.go: -------------------------------------------------------------------------------- 1 | package async 2 | 3 | // 异步执行类,提供异步执行的功能,可快速方便的开启异步执行 4 | // 通过NewAsync() 来创建一个新的异步操作对象 5 | // 通过调用 Add 函数来向异步任务列表中添加新的任务 6 | // 通过调用 Run 函数来获取一个接收返回的channel,当返回结果时将会返回一个map[string][]interface{} 7 | // 的结果集,包括每个异步函数所返回的所有的结果 8 | import ( 9 | "reflect" 10 | ) 11 | 12 | // 异步执行所需要的数据 13 | type asyncRun struct { 14 | Handler reflect.Value 15 | Params []reflect.Value 16 | } 17 | 18 | // Async 异步执行对象 19 | type Async struct { 20 | count int 21 | tasks map[string]asyncRun 22 | } 23 | 24 | // NewAsync 老版本的兼容 25 | func NewAsync() Async { 26 | return New() 27 | } 28 | 29 | // New 创建一个新的异步执行对象 30 | func New() Async { 31 | return Async{tasks: make(map[string]asyncRun)} 32 | } 33 | 34 | // Add 添加异步执行任务 35 | // name 任务名,结果返回时也将放在任务名中 36 | // handler 任务执行函数,将需要被执行的函数导入到程序中 37 | // params 任务执行函数所需要的参数 38 | func (a *Async) Add(name string, handler interface{}, params ...interface{}) bool { 39 | if _, e := a.tasks[name]; e { 40 | return false 41 | } 42 | 43 | handlerValue := reflect.ValueOf(handler) 44 | if handlerValue.Kind() == reflect.Func { 45 | 46 | paramNum := len(params) 47 | 48 | a.tasks[name] = asyncRun{ 49 | Handler: handlerValue, 50 | Params: make([]reflect.Value, paramNum), 51 | } 52 | 53 | if paramNum > 0 { 54 | for k, v := range params { 55 | a.tasks[name].Params[k] = reflect.ValueOf(v) 56 | } 57 | } 58 | 59 | a.count++ 60 | return true 61 | } 62 | 63 | return false 64 | } 65 | 66 | // Run 任务执行函数,成功时将返回一个用于接受结果的channel 67 | // 在所有异步任务都运行完成时,结果channel将会返回一个map[string][]interface{}的结果。 68 | func (a *Async) Run() (chan map[string][]interface{}, bool) { 69 | if a.count < 1 { 70 | return nil, false 71 | } 72 | result := make(chan map[string][]interface{}) 73 | chans := make(chan map[string]interface{}, a.count) 74 | 75 | go func(result chan map[string][]interface{}, chans chan map[string]interface{}) { 76 | rs := make(map[string][]interface{}) 77 | defer func(rs map[string][]interface{}) { 78 | result <- rs 79 | }(rs) 80 | for { 81 | if a.count < 1 { 82 | break 83 | } 84 | 85 | select { 86 | case res := <-chans: 87 | a.count-- 88 | rs[res["name"].(string)] = res["result"].([]interface{}) 89 | } 90 | } 91 | }(result, chans) 92 | 93 | for k, v := range a.tasks { 94 | go func(name string, chans chan map[string]interface{}, async asyncRun) { 95 | result := make([]interface{}, 0) 96 | defer func(name string, chans chan map[string]interface{}) { 97 | chans <- map[string]interface{}{"name": name, "result": result} 98 | }(name, chans) 99 | 100 | values := async.Handler.Call(async.Params) 101 | 102 | if valuesNum := len(values); valuesNum > 0 { 103 | resultItems := make([]interface{}, valuesNum) 104 | for k, v := range values { 105 | resultItems[k] = v.Interface() 106 | } 107 | result = resultItems 108 | return 109 | } 110 | }(k, chans, v) 111 | } 112 | 113 | return result, true 114 | } 115 | 116 | // Clean 清空任务队列. 117 | func (a *Async) Clean() { 118 | a.tasks = make(map[string]asyncRun) 119 | } 120 | --------------------------------------------------------------------------------