golang 依賴控制反轉(IoC)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

  主流開發語言,為了達到項目間的低耦合,都會藉助IoC架構來實現。即抽象和實現分離,使用抽象層,不用關心這些抽象層的具體實現;抽象層的實現,可以獨立實現。現在比較流行的領域驅動設計(ddd),為了達到將領域層作為最核心,也需要依賴於IOC。

  回過頭來,我們看看golang實現的ioc架構,有golang風格的架構,也有從其他主流語言搬過來的比較重的架構。我覺得目前實現最輕量級的,當屬martini架構的ioc依賴庫 github.com/codegangsta/inject  。程式碼數很少,提供類型註冊、介面註冊、類型解析、函數注入、struct注入的方法,可以說基本的已經比較全了。從文章開頭應該可以猜到,我現在一直在學習ddd,目前在.NET實際項目中邊運用邊學習。在實際使用中發現,ioc除了要有單例模式(Singleton)支援外,應該還有臨時執行個體(Transient)的支援。因此萌生了我寫golang下的ioc架構的原因。

  我的目的很簡單,希望ioc不僅支援Singleton,還要支援Transient。最初想法是,編寫一個抽象層,裡面支援這兩種模式的注入。其中transition部分自己獨立實現,而singleton,則採用現成的 github.com/codegangsta/inject 架構,並加一層適配。Transient的實現,其特點就是,每次解析類型(Resolve)時,都需要建立一個新的對象,這個對象和先前建立的是獨立的。此處我採用反射機制,根據類型建立新對象。golang中沒有建構函式,為了在建立對象後並在使用前,對其初始化,我引入了建構函式的概念。這個建構函式的介面其實很簡單

// Initializer is to init a struct.type Initializer interface {    InitFunc() interface{}}

  在這裡我吐槽下部落格園,怎麼插入代碼,還不支援golang啊?

  這個介面很簡單,就一個返回interface{}的函數。其實返回的應該是另一個函數,即為建構函式。例如:

func (container *iocContainer) InitFunc() interface{} {    return func() {        if !container.isInitialized {            container.locker = &sync.RWMutex{}            container.singleton = &singletonContainer{valuemapper: make(map[reflect.Type]reflect.Value)}            container.transient = &transientContainer{typemapper: make(map[reflect.Type]reflect.Type)}            container.isInitialized = true        }    }}

  當初始化時,調用一次建構函式,即完成了一次初始化的操作。其實針對singleton也是一樣,也需要一次初始化,只是這個初始化要求僅在第一次時進行,在這裡不會因此只調用一次(因為ioc架構不知道你什麼時候會被第一次調用,這裡需要由建構函式的實現自己進行判斷,此處可以用一個欄位isInitialized進行檢查是否已經初始化了)。

  都說golang的反射,效能很差,我覺得部分反射的部分功能會效能很差,但有些應該還算湊合吧。既然ioc架構實現完了,那就測試下效能。由於在調整前,效能資料沒有儲存,就不展示了。總之,在改版前,發現inject包,在Resolve的效能很差。經過仔細排查,發現有一處的實現很智能,即當Resolve的介面類型在已注入的類型中不存在時,會嘗試將已存在的類型轉為介面,如果可以轉換則返回。由於golang的理念裡,沒有類型樹。認為介面的方法都實現了,就認為實現了介面,那麼判斷本身就會變得耗時。也因為這個原因,我重寫了singleton部分,在Resolve的時候,僅僅根據傳入的類型來判斷。如果這個類型在註冊時為singleton,那就是singleton,且原先是介面還是類型,都原樣拿出,不進行任何轉換。果然發現效能有所提升。

  這是ioc容器的介面,也是最核心的:

// ReadonlyContainer is a readonly containertype ReadonlyContainer interface {    // Resolve is to get instance of type.    Resolve(typ reflect.Type) reflect.Value    // Invoke is to inject to function's params, such as construction.    Invoke(f interface{}) ([]reflect.Value, error)}// Container is a container for ioc.type Container interface {    Initializer    ReadonlyContainer    // Register is to register a type as singleton or transient.    Register(val interface{}, lifecycle Lifecycle)    // RegisterTo is to register a interface as singleton or transient.    RegisterTo(val interface{}, ifacePtr interface{}, lifecycle Lifecycle)    // SetParent is to resolve parent's container if current hasn't registered a type.    SetParent(parent ReadonlyContainer)}

  這是調用的代碼:

func main() {    var requestContext = ioc.NewContainer()    requestContext.SetParent(iocContainer)    requestContext.RegisterTo(&productcategoryApp.ProductCategoryApplicationServiceImpl{}, (*application.ProductCategoryApplicationService)(nil), ioc.Transient)    commandMQAdapter := new(provider.MyCommandMQProvider)    processor := cqrs.NewCommandProcessor(commandMQAdapter)    processor.RegisterMiddleware((*middleware.AuthCommandMiddleware)(nil))    // execute count    var exeCount = 1000000    // concurrent routine    var concurrentCount = 1    for true {        var wg *sync.WaitGroup = &sync.WaitGroup{}        time.Sleep(300 * time.Millisecond)        startTime := time.Now().UnixNano()        for i := 0; i < concurrentCount; i++ {            wg.Add(1)            go func(wg1 *sync.WaitGroup) {                for j := 0; j < exeCount/concurrentCount; j++ {                    requestContext.Invoke(func(productCategoryAppSvc application.ProductCategoryApplicationService, roContainer ioc.ReadonlyContainer) {                        //processor.RegisterHandler(productCategoryAppSvc)                    })                }                wg1.Done()            }(wg)        }        wg.Wait()        endTime := time.Now().UnixNano()        consoleLog.Printf("[info] requestContext.Invoke for %d times with %d routines execute in %vms.\n", exeCount, concurrentCount, float64(endTime-startTime)/float64(time.Millisecond))    }}

 

  這是效能資料:

1 routine, 3 times resolve singleton and 1 times resolve transient per code invoke, invoke 1,000,000 times.

Result:

[commandprocessor] 2016/07/17 11:31:29 [info] requestContext.Invoke for 1000000 times with 1 routines execute in 4971.1971ms.[commandprocessor] 2016/07/17 11:31:34 [info] requestContext.Invoke for 1000000 times with 1 routines execute in 4951.494214ms.[commandprocessor] 2016/07/17 11:31:39 [info] requestContext.Invoke for 1000000 times with 1 routines execute in 4954.376794ms.

2 routine, 3 times resolve singleton and 1 times resolve transient per code invoke, invoke 1,000,000 times.

Result:

[commandprocessor] 2016/07/17 11:23:50 [info] requestContext.Invoke for 1000000 times with 2 routines execute in 2779.720723ms.[commandprocessor] 2016/07/17 11:23:53 [info] requestContext.Invoke for 1000000 times with 2 routines execute in 2719.810844ms.[commandprocessor] 2016/07/17 11:23:56 [info] requestContext.Invoke for 1000000 times with 2 routines execute in 2734.028326ms.

   預估下來,差不多是 2 routine, 4 resolve action, 350,000 / sec 的效能資料。我是在筆記本上進行的測試(i5雙核),啟用2個並發routine來測試Resolve,每次測試代碼的一次執行,包含Resolve4次調用。測試下來,每秒35w次測試代碼執行。這個效能,我覺得在業務系統開發中,不需要考慮效能損耗的問題了。

---------------------------------分割線-------------------------------------------------------------

我的ioc項目,已經掛在github上,有興趣的可以去瞭解下。https://github.com/Berkaroad/ioc

通過go來安裝ioc包:  go get github.com/berkaroad/ioc

使用中有何問題,歡迎在github上給我提issue,謝謝!

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.