2015-07-22 4 views
10

ज्ञात के रूप में, कोई यूनियन प्रकार नहीं है, और केवल इंटरफ़ेस के माध्यम से अनुकरण किया जाना चाहिए।गोलांग: यूनियन प्रकार को कुशलतापूर्वक अनुकरण कैसे करें

मैं दो तरीकों की कोशिश संघ अनुकरण करने के लिए है, लेकिन परिणाम सी के रूप में अच्छा से दूर है

package main 

import (
    "fmt" 
    "time" 
) 

type U interface { 
    i32() int32 
    i16() int16 
} 

type i32 int32 

func (u i32) i32() int32 { 
    return int32(u) 
} 

func (u i32) i16() int16 { 
    return int16(u) 
} 

type i16 int16 

func (u i16) i32() int32 { 
    return int32(u) 
} 

func (u i16) i16() int16 { 
    return int16(u) 
} 

func test() (total int64) { 
    type A struct { 
     t int32 
     u interface{} 
    } 
    a := [...]A{{1, int32(100)}, {2, int16(3)}} 

    for i := 0; i < 5000000000; i++ { 
     p := &a[i%2] 
     switch p.t { 
     case 1: 
      total += int64(p.u.(int32)) 
     case 2: 
      total += int64(p.u.(int16)) 
     } 
    } 
    return 
} 

func test2() (total int64) { 
    type A struct { 
     t int32 
     u U 
    } 
    a := [...]A{{1, i32(100)}, {2, i16(3)}} 

    for i := 0; i < 5000000000; i++ { 
     p := &a[i%2] 
     switch p.t { 
     case 1: 
      total += int64(p.u.i32()) 
     case 2: 
      total += int64(p.u.i16()) 
     } 
    } 
    return 
} 

type testfn func() int64 

func run(f testfn) { 
    ts := time.Now() 
    total := f() 
    te := time.Now() 
    fmt.Println(total) 
    fmt.Println(te.Sub(ts)) 
} 

func main() { 
    run(test) 
    run(test2) 
} 

परिणाम:

257500000000 
1m23.508223094s 
257500000000 
34.95081661s 

विधि जिस तरह से बेहतर है, और टाइप-कास्ट रास्ता अधिक CPU समय लागत।

सी संस्करण:

#include <stdio.h> 

struct A { 
    int t; 
    union { 
     int i; 
     short v; 
    } u; 
}; 

long test() 
{ 
    struct A a[2]; 
    a[0].t = 1; 
    a[0].u.i = 100; 
    a[1].t = 2; 
    a[1].u.v = 3; 

    long total = 0; 
    long i; 
    for (i = 0; i < 5000000000; i++) { 
     struct A* p = &a[i % 2]; 
     switch(p->t) { 
     case 1: 
      total += p->u.i; 
      break; 
     case 2: 
      total += p->u.v; 
      break; 
     } 
    } 
    return total; 
} 
int main() 
{ 
    long total = test(); 
    printf("%ld\n", total); 
} 

परिणाम:

257500000000 

real 0m5.620s 
user 0m5.620s 
sys 0m0.000s 

संघ प्रकार कई अनुप्रयोगों, जैसे के लिए उपयोगी है नेटवर्क प्रोटोकॉल में वेरिएंट कंक्रीट प्रकार हो सकता है। तो शायद यूनियन डेटा की पहुंच एप्लिकेशन की बाधा बन सकती है।

कोई भी मदद कर सकता है? धन्यवाद।

उत्तर

6

आप सरणियों उपयोग कर सकते हैं एक भी int32 दो के रूप में int16 रों प्रतिनिधित्व करते हैं और फिर उन्हें बदलाव as Rob Pike recommends साथ इकट्ठा करने के लिए:

func test3() (total int64) { 
    type A struct { 
     t int32 
     u [2]int16 
    } 
    a := [...]A{ 
     {1, [2]int16{100, 0}}, 
     {2, [2]int16{3, 0}}, 
    } 

    for i := 0; i < N; i++ { 
     p := &a[i%2] 
     switch p.t { 
     case 1: 
      total += int64(p.u[0]<<0 | p.u[1]<<8) 
     case 2: 
      total += int64(p.u[0]) 
     } 
    } 
    return 
} 

मूल जाओ संकलक इसके बारे में 2 बार सी संस्करण की तुलना में धीमी चलाता है के साथ, और साथ gccgo (-O3) यह सी

के रूप में तेज़ी से चलता है हालांकि यह दृष्टिकोण चेतावनी दी जाती है कि यह दृष्टिकोण थोड़ा-अंतराल इंट्स मानता है। आपको बड़े-एंडियन आर्किटेक्चर के लिए बदलावों के क्रम को स्विच करने की आवश्यकता होगी।

इसके अलावा, यदि आपको बाइट स्लाइस से संरचनाओं को डीकोड करने की आवश्यकता है, तो आपको वास्तव में encoding/binary का उपयोग करना चाहिए। यह लाइब्रेरी बाइट अनुक्रमों और अन्य प्रकारों के बीच अनुवाद करने के लिए बनाई गई है।

+1

हां, यह प्रदर्शन में सुधार कर सकता है, लेकिन कभी-कभी संस्करण प्रकार में अन्य प्रकार शामिल हो सकते हैं, उदा। स्ट्रिंग या बाइट सरणी। – kingluo

+0

संपादित देखें। मैंने 'असुरक्षित' के उपयोग हटा दिए हैं क्योंकि इसकी वास्तव में आवश्यकता नहीं है और अन्य प्रकारों के बारे में एक नोट जोड़ा गया है। –

+1

धन्यवाद। मैं द्विआधारी कार्यों का प्रयास करता हूं, वे बहुत महंगे लगते हैं। चूंकि संघ तार प्रारूप होने का इरादा नहीं रखता है, इसलिए संख्यात्मक प्रकारों के लिए बाइनरी प्रतिनिधित्व आवश्यक नहीं है। मुझे लगता है कि असुरक्षित मेरे मामले में और अधिक समझ में आता है। – kingluo

2

संघ में संख्यात्मक प्रकार और ऑक्टेट स्ट्रिंग हो सकती है, इसलिए मैं बाइट स्लाइस को वैल्यू कंटेनर के रूप में उपयोग करने का प्रयास करता हूं और कंक्रीट प्रकार के अनुसार इसे एक्सेस करने के लिए unsafe.Pointer का उपयोग करता हूं।

func test3() (total int64) { 
    type A struct { 
     t int32 
     u []byte 
    } 

    a := [...]A{{1, make([]byte, 8)}, {2, make([]byte, 8)}} 
    *(*int32)(unsafe.Pointer(&a[0].u)) = 100 
    *(*int16)(unsafe.Pointer(&a[1].u)) = 3 

    for i := 0; i < 5000000000; i++ { 
     p := &a[i%2] 
     switch p.t { 
     case 1: 
      total += int64(*(*int32)(unsafe.Pointer(&p.u))) 
     case 2: 
      total += int64(*(*int16)(unsafe.Pointer(&p.u))) 
     } 
    } 
    return 
} 

परिणाम:

$ go run union.go 
257500000000 
12.844752701s 

$ go run -compiler gccgo -gccgoflags -O3 union.go 
257500000000 
6.640667s 

यह सबसे अच्छा संस्करण है?

+0

स्लाइस के बजाय सरणी (या सरणी के लिए पॉइंटर्स) का उपयोग सैद्धांतिक रूप से प्रदर्शन में सुधार कर सकता है। –

+0

मैं बाइट सरणी का प्रयास करता हूं, लेकिन प्रदर्शन लगभग समान है। वैसे भी, मेरे मामले में, ऑक्टेट स्ट्रिंग चर लंबाई में है, इसलिए बाइट टुकड़ा एकमात्र विकल्प होना चाहिए। – kingluo

संबंधित मुद्दे