Hi,
the following questions are open:
1. example:
package main
type first struct {
}
func (this *first) self1() {
println("*first=", this)
}
type second struct {
first
}
func (this *second) self2() {
println("*second=", this)
}
func main() {
x := new(second)
x.self1()
x.self2()
}
1. result:
*first= 0x7fc7769c7000
*second= 0x7fc7769c7000
Why are the both pointers equal ?
2.example
package main
type first struct {
}
func (this *first) self() {
println("*first=", this)
}
type second struct {
first
}
func (this *second) self() {
println("*second=", this)
}
func main() {
x := new(second)
x.self()
x.self()
}
2. result
*second= 0x7f6ea09c1000
*second= 0x7f6ea09c1000
How I call the "self" method from "first" ?
func main() {
x := new(second)
first(x).self()
x.self()
}
> test2.go:21: cannot convert x (type *second) to type *first
Why I cannot convert even if the pointers are equal ?
And the most important question:
How I can call a method of "second" from "first" without knowing
"second" in "first" ?
mfg, Andreas Otto (aotto1968)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5PXNAAoJEGTcPijNG3/Aj68H/A9cLxuOQt69lJfGrpbBVx5u
8zWp0MPP4aFZXjLFRu7tHmm3s66kAU+QWJCJ8Ki3wVBheDgWMFBQOn5fA00f2LNS
C6INuL2z1s2xtmEie+6apwkQlgtAGbah1DIUehuM16Cp6s1uU3wC3ZbfgcQs8XEM
TZ5e3M1eqFIbUL6iLbi/Ht6/32h/59hv/R6+lT+RPaLpoUaRWyvNAivIDcmjF52h
rQU5CS2KnbZnp4uEcd29E/AikzeIin3yv+KMJXE9uVu89sgMuTO+uf+Dmex+hbSZ
fVLrQNus47/YYonGhR+nGLlCDqwvVNNOv+hZhW7A5/UTKgZC5De7FOhim9SLQhM=
=Y0qJ
-----END PGP SIGNATURE-----
> the following questions are open:
>
> 1. example:
> package main
>
> type first struct {
> }
>
> func (this *first) self1() {
> println("*first=", this)
> }
>
> type second struct {
> first
> }
>
> func (this *second) self2() {
> println("*second=", this)
> }
>
> func main() {
> x := new(second)
> x.self1()
> x.self2()
> }
> 1. result:
> *first= 0x7fc7769c7000
> *second= 0x7fc7769c7000
>
> Why are the both pointers equal ?
Why would they not be? The `first` field of `second` will
start at the beginning of `second` -- there's no reason I can
see that there would be padding added.
> 2.example
...
> How I call the "self" method from "first" ?
x.first.self()
> func main() {
> x := new(second)
> first(x).self()
> x.self()
> }
>> test2.go:21: cannot convert x (type *second) to type *first
>
> Why I cannot convert even if the pointers are equal ?
They're of unrelated types. It doesn't matter if their underlying
address values are equal or not.
> And the most important question:
>
> How I can call a method of "second" from "first" without knowing
> "second" in "first" ?
You can't. You'll have to Make Arrangements. Which Arrangements
you make will depend on exactly what sort of effect you want.
What sort of effect do you want?
Chris
--
Chris "allusive" Dollin
If T is a type which has a method named M with arguments of types
U, V, ..., (and maybe result types X, Y, ...) then
T.M
is a function with argument types T, U, V, ... (and maybe result types
X, Y ...).
[That's a meta ..., not an in-Go ...]
Hi,
thanks for the answer...
>> And the most important question:
>>
>> How I can call a method of "second" from "first" without knowing
>> "second" in "first" ?
>
> You can't. You'll have to Make Arrangements. Which Arrangements
> you make will depend on exactly what sort of effect you want.
>
> What sort of effect do you want?
>
> Chris
>
I want to code a classical class hierarchy like in C#
using System;
using csmsgque;
namespace example {
sealed class mulserver : MqS, IServerSetup, IFactory {
MqS IFactory.Factory() {
return new mulserver();
}
public void MMUL () {
SendSTART();
SendD(ReadD() * ReadD());
SendRETURN();
}
void IServerSetup.ServerSetup() {
ServiceCreate("MMUL", MMUL);
}
static void Main(string[] argv) {
mulserver srv = new mulserver();
try {
srv.ConfigSetName("MyMulServer");
srv.LinkCreate(argv);
srv.ProcessEvent(MqS.WAIT.FOREVER);
} catch (Exception ex) {
srv.ErrorSet (ex);
}
srv.Exit();
}
}
}
The base class "MqS" has the "technology" and the
toplevel class "server" has the callbacks.
In the call above the toplevel class "server" has the
callback "MMUL" and this callback is called from code
behind the class "MqS"
The link between the callback of the toplevel class
"server" and the base class "MqS" is done using the
base class method "ServiceCreate"
in our case: ServiceCreate("MMUL", MMUL)
is this clear ?
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5QB9AAoJEGTcPijNG3/AW6sH/3Po/ptujjr4ciACQWS8JVi0
1hEnom7l/wOe7iTKCdTRGmKBZgjwICZ+FltGDT1JuA2tP9iNXznuD2bT/Va8jr+1
fz4KGNFn1tCWzlPVJIOMi5PU1I2onWqqvHKdwIXvTGuTZ77ivciY1//uS41tv8CX
wK3sfGcJ9xBpXf6DqS9TRhvbgxQqImH98xMiBNv4NulVlZ9KdptSSI2HdvGdLbhI
WSawB85HLs6qPqpXjY/C+igpUAelSOp/+ahBc5Dqlx34NnuguQKwoy4PQf5O0xOx
lrnexPEUNfySW4WfaBDAmjDeSIdW8lYJDd2GNyzljnRNAZ23BDt+v4/mMnfHuAE=
=ksXm
-----END PGP SIGNATURE-----
they're both equal because both structs
are at the same place in memory (although
they have different types).
it's similar to the way it works in C:
typedef struct first first;
typedef struct second second;
struct first {};
struct second {first embedded;};
void self1(first *this) {
printf("*first = %p\n", this);
}
void self2(second *this) {
printf("*second = %p\n", this);
}
void foo(void) {
second *x;
x = malloc(sizeof(second));
self1(&x->embedded);
self2(x);
}
> 2.example
> package main
>
> type first struct {
> }
>
> func (this *first) self() {
> println("*first=", this)
> }
>
> type second struct {
> first
> }
>
> func (this *second) self() {
> println("*second=", this)
> }
>
> func main() {
> x := new(second)
> x.self()
> x.self()
> }
> 2. result
> *second= 0x7f6ea09c1000
> *second= 0x7f6ea09c1000
>
> How I call the "self" method from "first" ?
there are two self methods. which one do you mean?
you need to understand that there is no inheritance in Go,
only embedding. first cannot be aware that it is embedded
inside second. Go is different from conventional OO
languages in this respect.
> func main() {
> x := new(second)
> first(x).self()
> x.self()
> }
>> test2.go:21: cannot convert x (type *second) to type *first
i don't get that error. i get
tst.go:20: cannot convert x (type *second) to type first
which makes more sense, because first(x) is trying to
convert x to type first.
but even if you had (*first)(x).self() it would still be incorrect.
> Why I cannot convert even if the pointers are equal ?
the pointers are equal, but the types are different.
(&x.first).self() would work.
> And the most important question:
>
> How I can call a method of "second" from "first" without knowing
> "second" in "first" ?
you can't - go does not do subclassing.
if you really want first to be able to call second, then you
second must pass in the means to do so (e.g. a function pointer).
don't think subclassing - think embedding and composition.
you'd need to create a closure.
func main() {
x := new(second)
y := F(misc)
z0 := F(func() { x.self1() })
z1 := F(func() { x.self2() })
z0()
z1()
y()
}
Hi, a example says more than words ....
package main
type F func()
type G func (*second) ()
type first struct {
}
func (this *first) self() {
println("*first=", this)
}
type second struct {
first
}
func (this *second) self() {
println("*second=", this)
}
func misc() {
println("misc")
}
func main() {
x := new(second)
y := F(misc)
z := G((*second).self)
x.first.self()
x.self()
y()
x.z(x)
}
result
> 6g test2.go
test2.go:29: z declared and not used
test2.go:33: x.z undefined (type second has no field or method z)
Q: How does I call a method through a function pointer reference
in our case using "z"
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5QPuAAoJEGTcPijNG3/A22EH/0gWPYsDlHoCcNdrGKHtH4FH
szSdKUxGlhr3xmTaM4lB15f3E14c8TfHixRg/2u1vFj1EJMRi4Y5Xm0Eo20BFZPV
+HWAD/Rk4gqm1qpXG9O1gRTUPvSVEJULO8DeJZulYuadFIstcF/oL1jJfGuYJLFr
M1GsLl33BuVSM5GmJZZS6q6nkvR3vGMsCKHK/Vecj19LNG4GnpjtXIr7oFQa5WYq
P9BzNGsRGpvLBvqg50KIMAqQOZ+D7Y7cwYa/WwV53QCYMRuuguLESSNAHyL3RIuG
tr4nTwyYUiZMROJTSLDhLqGv17Nj2an+IjX42yxU7HTalTDty0Vev752ekKbqSc=
=WLOW
-----END PGP SIGNATURE-----
Hi,
this works
func main() {
x := new(second)
y := F(misc)
z := F(func() { x.self() })
x.first.self()
x.self()
y()
z()
}
result:
> ./test2
*first= 0x7f95c4a020f8
*second= 0x7f95c4a020f8
misc
*second= 0x7f95c4a020f8
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5QUnAAoJEGTcPijNG3/A0hQH/2qzvF1BvYo5UKbHYKZw+V/V
KrEL5bPR79EQS9D3H+5An9RNPaH6bVDsM4JVfq4F4px2wPa0xGecXCk4O6m3YXlU
ZEbYYhCOaf5kymQsVXdogBG1qp/1h+3IOVmZoxX9mmEgFTjt7KxHkjkMpieqXHPj
Sfg5sZwpCMF1y6p4zJDykNO/2vSCNUb8QXariHOmUwTt+jLt7hhr/9JElEAMSq1y
lxsy/dNOLmwvHUHmqEWZauxdXQIaDP+7N2Ug+8E5zaeTcMl8807RfPU7t5tkg9A0
n17y0oa+wV9f0txE76gkgKs0ALPgD2X1sBS1ngjk4NS9DXBWsw/wGQEt42HJK1Y=
=vqAy
-----END PGP SIGNATURE-----
don't!
Go does not do class hierarchies.
I know, but with "embedding" and "closures"
I think I can the behavior from above
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5QhaAAoJEGTcPijNG3/AZv4H/3TzDy6EjWCvV2Ij5l1XOOBI
uV3m1PWVPPfTXud3Nzka2kKr9NiCOraOXOa6BkoRw667nAhVGLZ9AVGeXYw34TIh
EQnFy2UW8tI48s+eQV4hK6Wmk9w1HnAI+mz270d1GHqMDuVbNC1IZ4zt0PTCxPvM
u+2qdFC0AJ31GhcJX7nTPEjjSuLc0GHJF9/+PoMJFOX5wYMCKqykUvDuV5dlZ711
/qa8Xd0vIlNVdVCxsw895uu85Kmv1SmbW087ob3jVwjKFiamtVVxVvrDQKwcDUtJ
cnfEw3nCpV9CRci70PtmRPEk+74ySwJ1h4cLtUkx3oX4AfrDOqPzFgu0nlvalgw=
=EbHx
-----END PGP SIGNATURE-----
the classical Go way to do this kind of thing would
be to pass in an interface representing the callbacks.
but for your instance, i'm not sure that's necessary.
you could just pass in a MqS instance:
type MqS ...
func (m *MqS) SendSTART()
func (m *MqS) ReadD() int
func (m *MqS) SendD(int)
func (m *MqS) SendRETURN()
type Service struct {
*MqS
...
}
func ServiceCreate(m *MqS) *Server {
// a more conventional name might be "NewService".
return &Service{m, ...}
}
func (s *Service) MMUL() {
s.SendSTART();
s.SendD(s.ReadD() * s.ReadD());
s.SendRETURN();
}
does that start to make sense?
> I want to code a classical class hierarchy like in C#
Probably not such a good move. Go deliberately doesn't support
"classical" subclassing & has other pieces of machinery for solving
the problems that subclassing is for solving.
In the example you present, I'd have the "base class", the
thing like MqS, take either a (or some) function(s), or an
object satisfying an interface, to do the superclassy thing.
Something like this:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
package main
import "fmt"
type Base struct {
superMethod func ()
}
func (b *Base) BaseMethod() {
b.superMethod()
}
func (b *Base) Init(f func()) {
b.superMethod = f
}
type Super struct {
Base
}
func (s *Super) Init() {
s.Base.Init( func() { s.calledBack() } )
}
func (s *Super) calledBack() {
fmt.Println( "I have been called back" )
}
func main() {
var S Super
S.Init()
S.BaseMethod()
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
The "base class" Base has a function pointer for the callback
that it runs when BaseMethod is called. Here I've established
that pointer by calling an Init method -- other ways might be used.
The "superclass" Super embed a Base, which means BaseMethod
can be invoked on it. Super's Init method calls the Base init method
for this Super passing in a closure which calls calledBack on this
Super instance.
looks interesting, a little bit like java ...
package example;
import javamsgque.*;
final class mulserver extends MqS implements IServerSetup, IFactory {
class MMUL implements IService {
public void Service (MqS ctx) throws MqSException {
SendSTART();
SendD(ReadD() * ReadD());
SendRETURN();
}
}
public void ServerSetup() throws MqSException {
ServiceCreate("MMUL", new MMUL());
}
public MqS Factory() {
return new mulserver();
}
public static void main(String[] argv) {
MqS.Init("java", "example.mulserver");
mulserver srv = new mulserver();
try {
srv.ConfigSetName("MyMulServer");
srv.LinkCreate(argv);
srv.ProcessEvent(MqS.WAIT.FOREVER);
} catch (Throwable e) {
srv.ErrorSet(e);
}
srv.Exit();
}
}
java need a subclass for this kind of cooding
the core problem of your example is that usually
multiple sercives are provided ...
mfg, andreas otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5QxvAAoJEGTcPijNG3/A0PoH/igxY8QKPof1UaYYEUSQ1e/G
EwlU+LkNgaLT5oUJ6wPGupzKrcfQF2/7pO11d/WmRbt2dTh68RR/gct6uzNWUknE
UXz36SKrAJyaQgy9e6x1sFxmW3ldHxQmd+sdMl2aOR5Xp6I/+CdEYeM/Jg+51CBG
tFZCdw/IARiClNf8fOilSGoZUzUV78IJcAUefi0uq/UHMDKMyFMAHzDyO4yQrtav
DeQgGnSnDtBsgHT0nYcH+inWlctlspsM60vHU5JkJN6euCjKjhnOT9ibJQQtnkOG
tkS0pdUTI+crB2meV0Jz46P0fbUbzbiz9Cd2tq+43BFHGVgUlmNTOSd8CK/Cgdk=
=B9bI
-----END PGP SIGNATURE-----
in that case you need to think what all the services
have in common and define an interface that
represents that functionality.
then define your service publishing code
such that it takes that interface and does
whatever it needs with it.
go is all about *using* not *being used by*.
think active, not passive; functionality not frameworks.
Hi,
I analyze this code but I have a problem.
I have one "Server" but multiple "Services"
All "Services" share "Server" local variables
1. my problem is that I have one additional level of "indirection" using
the following construct
- -> MqCallback(func() {ret.ServerSetup()})
All together I have the following Wrappers to call an arbitrary GO method
1. Wrapper in C
2. Wrapper in GO
3. func() wrapper in GO
4. finally -> method
- -> goal for now, I want to skip level "3"
for unique known Methods like "ServerSetup" I can use "interface" but
I need for "1" *and* "2" an "interface" specific code ... bad
- -> but I#ll go this way
the problem are still the services, because the method-name is user
specific
but, step by step I come closer for a solution of the services problem
- -> I'll go the JAVA way
brainstorm ..
now the result, (only the toplevel code ...)
package main
import (
. "gomsgque"
"os"
)
type Server struct {
*MqS
incr int32
}
func NewServer() *Server {
ret := &Server{NewMqS(),10}
println("NewServer...", ret)
ret.ConfigSetServerSetup(ret)
return ret
}
func (this *Server) ServerSetup() {
this.ServiceCreate("ECOI", &ECOI{this})
// ... many, many services ....
}
// Q: would like to skip the next 3 lines -> just overhead
type ECOI struct {
*Server
}
func (this *ECOI) Call() {
this.SendSTART()
// !attention! call "*Server" variable "incr"
this.SendI(this.ReadI() + this.incr)
this.SendRETURN()
}
func main() {
var srv = NewServer()
defer func() {
if x := recover(); x != nil {
srv.ErrorSet(x)
}
srv.Exit()
}()
srv.ConfigSetName("server")
srv.ConfigSetIdent("test-server")
srv.LinkCreate(os.Args...)
srv.LogC("test",1,"this is the log test\n")
srv.ProcessEvent(MqS_TIMEOUT_DEFAULT, MqS_WAIT_FOREVER)
}
and the results ... (works!!!!)
> ./client @ ./server
NewMqS... 0x71d010
C> ((null):12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: START
NewMqS... 0x72b010
NewServer... 0x7fecbbffd200
1. ConfigSetServerSetup ... (0x7fecbbfbf5d0,0x7fecbbffd200)
S> (server:12766:0x7fecbc0cb700) [2010-11-19:10-56-40]
[0-0-1-0x72b010-sServerSetup]: INFO
S> (server:12766:0x7fecbc0cb700) [2010-11-19:10-56-40]
[0-0-1-0x72b010-cServerSetup]: 1111111111111111111111
1. ServiceCreate ... (0x7fecbbfbf540,0x7fecbbfaa0e8)
C> (client:12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: SEND
S> (server:12766:0x7fecbc0cb700) [2010-11-19:10-56-40]
[0-0-3-0x72b010-sService]: INFO
S> (server:12766:0x7fecbc0cb700) [2010-11-19:10-56-40]
[0-0-3-0x72b010-cService]: 1111111111111111111111
C> (client:12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: READ
C> (client:12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: RESULT = 110
C> (client:12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: END
iErrorMqToGoWithCheck...
ErrorSet...
Q: how does the code look like ... OK?
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5kuSAAoJEGTcPijNG3/AnDsH/RW1IifwLpObysE5rlDahTZ2
o9C2K+/KQAEZQh3g7JCjZuh5U14PpYZRn2aDE5Zq58lemLm7zsqeY7aIG7LGi6Pe
u1GQvKbxUk5yir1FxSE+m5eTQxdkW7KeFf+TIPgA12kBRUz0KawJNGucKKFIHclP
km78C6GUibC4O4EQMRI8CIc6KHnLeLBYxP2pWT6F+OxRnbhW5icyssqaoa3ZE9OJ
kPFg3csU1OAHzWyZHKHl/Jo3RZWpSFoVinFS0d60iwDAJcUOgqO8C425zFGdaCFH
eOCMnflaXxWBaq0tkWx2RfjxwNV+YJ69UAoczMb5reLDlV7zzifpvd1rGj/JHQs=
=PE3m
-----END PGP SIGNATURE-----
Hi,
as requested the other code as well....
/**
* \file theLink/gomsgque/src/MqS.go
* \brief \$Id: MqS.go 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
package gomsgque
/*
#include <gomsgque.h>
*/
import "C"
import (
//"fmt"
"unsafe"
//"reflect"
)
type TIMEOUT C.MQ_TIME_T
type WAIT uint32
const (
MqS_TIMEOUT_DEFAULT TIMEOUT = C.MQ_TIMEOUT_DEFAULT
MqS_TIMEOUT_USER TIMEOUT = C.MQ_TIMEOUT_USER
MqS_TIMEOUT_MAX TIMEOUT = C.MQ_TIMEOUT_MAX
MqS_WAIT_NO WAIT = C.MQ_WAIT_NO
MqS_WAIT_ONCE WAIT = C.MQ_WAIT_ONCE
MqS_WAIT_FOREVER WAIT = C.MQ_WAIT_FOREVER
)
type MqS _Ctype_struct_MqS
type MqSCallback func()
type IServerSetup interface {
ServerSetup()
}
type IServerCleanup interface {
ServerCleanup()
}
type IService interface {
Call()
}
func NewMqS() *MqS {
this := C.MqContextCreate(0,nil)
C.MqConfigSetSelf(this, unsafe.Pointer(this))
println("NewMqS...", this)
return (*MqS)(this)
}
func (this *MqS) String() string {
return C.GoString(C.MqErrorGetText((*_Ctype_struct_MqS)(this)))
}
func (this *MqS) LogC(prefix string, level int, message string) {
p := C.CString(prefix)
m := C.CString(message)
C.MqLogC((*_Ctype_struct_MqS)(this), p, C.MQ_INT(level), m)
C.free(unsafe.Pointer(m))
C.free(unsafe.Pointer(p))
}
func (this *MqS) Exit() {
C.MqExitP(C.sGO, (*_Ctype_struct_MqS)(this))
}
/**
* \file theLink/gomsgque/src/MqSException.go
* \brief \$Id: MqSException.go 314 2010-11-19 09:13:00Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 314 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
package gomsgque
/*
#include <gomsgque.h>
*/
import "C"
import (
//"fmt"
"unsafe"
"os"
)
func (this *MqS) iErrorMqToGoWithCheck(ex uint32) {
if (ex == C.MQ_ERROR) {
println("iErrorMqToGoWithCheck...")
panic(this)
}
}
func (this *MqS) ErrorSet(ex interface{}) {
println("ErrorSet...")
if ctx,ok := ex.(*MqS); ok {
C.MqErrorCopy((*_Ctype_struct_MqS)(this), (*_Ctype_struct_MqS)(ctx))
} else if err,ok := ex.(os.Error); ok {
m := C.CString(err.String())
C.MqErrorC((*_Ctype_struct_MqS)(this), C.sGO, -1, m)
C.free(unsafe.Pointer(m))
} else {
C.MqErrorC((*_Ctype_struct_MqS)(this), C.sGO, -1, C.sUNKNOWN)
}
}
func (this *MqS) ErrorC(prefix string, level int, message string) {
p := C.CString(prefix)
m := C.CString(message)
C.MqErrorC((*_Ctype_struct_MqS)(this), p, C.MQ_INT(level), m)
C.free(unsafe.Pointer(p))
C.free(unsafe.Pointer(m))
}
func (this *MqS) ErrorSetCONTINUE() {
C.MqErrorSetCONTINUE((*_Ctype_struct_MqS)(this))
}
func (this *MqS) ErrorSetEXIT() {
r := C.MqErrorSetEXITP((*_Ctype_struct_MqS)(this),C.sGO)
this.iErrorMqToGoWithCheck(r)
}
func (this *MqS) ErrorIsEXIT() bool {
return C.MqErrorIsEXIT((*_Ctype_struct_MqS)(this)) == C.MQ_YES
}
func (this *MqS) ErrorReset() {
C.MqErrorReset((*_Ctype_struct_MqS)(this))
}
func (this *MqS) ErrorPrint() {
C.MqErrorPrint((*_Ctype_struct_MqS)(this))
}
/**
* \file theLink/gomsgque/src/MqBinary.go
* \brief \$Id: MqBinary.go 310 2010-11-17 16:21:48Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 310 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
package gomsgque
/*
#include <gomsgque.h>
*/
import "C"
import (
//"fmt"
//"strings"
"unsafe"
)
type MqBinary struct {
D unsafe.Pointer
L int
}
func (this MqBinary) array() []byte {
byt := make([]byte, this.L)
C.memcpy(unsafe.Pointer(&byt[0]),this.D,C.size_t(this.L))
return byt
}
func (this MqBinary) string() string {
return C.GoStringN((*C.char)(this.D), C.int(this.L))
}
/**
* \file theLink/gomsgque/src/send.go
* \brief \$Id: send.go 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
package gomsgque
/*
#include <gomsgque.h>
*/
import "C"
import (
//"fmt"
//"strings"
"unsafe"
)
func (this *MqS) SendSTART() {
this.iErrorMqToGoWithCheck(C.MqSendSTART((*_Ctype_struct_MqS)(this)))
}
func (this *MqS) SendEND_AND_WAIT(token string, timeout TIMEOUT) {
t := C.CString(token)
r := C.MqSendEND_AND_WAIT((*_Ctype_struct_MqS)(this), t,
C.MQ_TIME_T(timeout))
C.free(unsafe.Pointer(t))
this.iErrorMqToGoWithCheck(r)
}
func (this *MqS) SendRETURN() {
this.iErrorMqToGoWithCheck(C.MqSendRETURN((*_Ctype_struct_MqS)(this)))
}
func (this *MqS) SendI(val int32) {
this.iErrorMqToGoWithCheck(C.MqSendI((*_Ctype_struct_MqS)(this),
C.MQ_INT(val)))
}
/**
* \file theLink/gomsgque/src/read.go
* \brief \$Id: read.go 314 2010-11-19 09:13:00Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 314 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
package gomsgque
/*
#include <gomsgque.h>
*/
import "C"
import (
//"fmt"
//"strings"
"unsafe"
)
func (this *MqS) ReadO() bool {
tmp := C.MQ_BOL(0)
this.iErrorMqToGoWithCheck(C.MqReadO((*_Ctype_struct_MqS)(this), &tmp))
return tmp != C.MQ_BOL(0)
}
func (this *MqS) ReadY() int8 {
tmp := C.MQ_BYT(0)
this.iErrorMqToGoWithCheck(C.MqReadY((*_Ctype_struct_MqS)(this), &tmp))
return int8(tmp)
}
func (this *MqS) ReadS() int16 {
tmp := C.MQ_SRT(0)
this.iErrorMqToGoWithCheck(C.MqReadS((*_Ctype_struct_MqS)(this), &tmp))
return int16(tmp)
}
func (this *MqS) ReadI() int32 {
tmp := C.MQ_INT(0)
this.iErrorMqToGoWithCheck(C.MqReadI((*_Ctype_struct_MqS)(this), &tmp))
return int32(tmp)
}
func (this *MqS) ReadW() int64 {
tmp := C.MQ_WID(0)
this.iErrorMqToGoWithCheck(C.MqReadW((*_Ctype_struct_MqS)(this), &tmp))
return int64(tmp)
}
func (this *MqS) ReadF() float32 {
tmp := C.MQ_FLT(0.0)
this.iErrorMqToGoWithCheck(C.MqReadF((*_Ctype_struct_MqS)(this), &tmp))
return float32(tmp)
}
func (this *MqS) ReadD() float64 {
tmp := C.MQ_DBL(0.0)
this.iErrorMqToGoWithCheck(C.MqReadD((*_Ctype_struct_MqS)(this), &tmp))
return float64(tmp)
}
func (this *MqS) ReadN() MqBinary {
var tmp C.MQ_CBI
len := C.MQ_SIZE(0)
this.iErrorMqToGoWithCheck(C.MqReadN((*_Ctype_struct_MqS)(this), &tmp,
&len))
return MqBinary{unsafe.Pointer(tmp), int(len)}
}
func (this *MqS) ReadB() MqBinary {
var tmp C.MQ_BIN
len := C.MQ_SIZE(0)
this.iErrorMqToGoWithCheck(C.MqReadB((*_Ctype_struct_MqS)(this), &tmp,
&len))
return MqBinary{unsafe.Pointer(tmp), int(len)}
}
func (this *MqS) ReadU() C.MQ_BUF {
var tmp C.MQ_BUF
this.iErrorMqToGoWithCheck(C.MqReadU((*_Ctype_struct_MqS)(this), &tmp))
return tmp
}
func (this *MqS) ReadL_START(buf C.MQ_BUF) {
this.iErrorMqToGoWithCheck(C.MqReadL_START((*_Ctype_struct_MqS)(this),
buf))
}
func (this *MqS) ReadL_END() {
this.iErrorMqToGoWithCheck(C.MqReadL_END((*_Ctype_struct_MqS)(this)))
}
func (this *MqS) ReadT_START(buf C.MQ_BUF) {
this.iErrorMqToGoWithCheck(C.MqReadT_START((*_Ctype_struct_MqS)(this),
buf))
}
func (this *MqS) ReadT_END() {
this.iErrorMqToGoWithCheck(C.MqReadT_END((*_Ctype_struct_MqS)(this)))
}
func (this *MqS) ReadProxy(ctx *MqS) {
this.iErrorMqToGoWithCheck(C.MqReadProxy((*_Ctype_struct_MqS)(this),
(*_Ctype_struct_MqS)(ctx)))
}
func (this *MqS) ReadGetNumItems(ctx *MqS) uint32 {
return uint32(C.MqReadGetNumItems((*_Ctype_struct_MqS)(this)))
}
/**
* \file theLink/gomsgque/src/link.go
* \brief \$Id: link.go 314 2010-11-19 09:13:00Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 314 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
package gomsgque
/*
#include <gomsgque.h>
*/
import "C"
import (
//"fmt"
//"strings"
"unsafe"
)
func (this *MqS) LinkCreate(argv ... string) {
var largv *_Ctype_struct_MqBufferLS
//fmt.Println("argv = " + strings.Join(argv,","))
if (len(argv) != 0) {
largv = C.MqBufferLCreate(C.MQ_SIZE(len(argv)));
for idx:= range argv {
a := C.CString(argv[idx])
C.MqBufferLAppendC(largv, a);
C.free(unsafe.Pointer(a))
}
}
this.iErrorMqToGoWithCheck(C.MqLinkCreate((*_Ctype_struct_MqS)(this),
&largv))
}
/**
* \file theLink/gomsgque/src/config.go
* \brief \$Id: config.go 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
package gomsgque
/*
#include <gomsgque.h>
*/
import "C"
import (
"fmt"
"unsafe"
)
func (this *MqS) ConfigSetName(val string) {
v := C.CString(val)
C.MqConfigSetName((*_Ctype_struct_MqS)(this), v)
C.free(unsafe.Pointer(v))
}
func (this *MqS) ConfigSetIdent(val string) {
v := C.CString(val)
C.MqConfigSetIdent((*_Ctype_struct_MqS)(this), v)
C.free(unsafe.Pointer(v))
}
//export cServerSetup
func (this *MqS) cServerSetup(cb *IServerSetup) {
defer func() {
if x := recover(); x != nil {
this.ErrorSet(x)
}
}()
this.LogC("cServerSetup",0,"1111111111111111111111\n")
(*cb).ServerSetup()
}
func (this *MqS) ConfigSetServerSetup(cb IServerSetup) {
println("1. ConfigSetServerSetup ... ", cb)
C.gomsgque_ConfigSetServerSetup((*_Ctype_struct_MqS)(this),
unsafe.Pointer(&cb))
}
func (this *MqS) ConfigSetServerCleanup(cb IServerCleanup) {
fmt.Printf("ConfigSetServerCleanup ... %T\n", cb)
C.MqConfigSetServerCleanup((*_Ctype_struct_MqS)(this), nil, nil, nil, nil)
}
/**
* \file theLink/gomsgque/src/service.go
* \brief \$Id: service.go 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
package gomsgque
/*
#include <gomsgque.h>
*/
import "C"
import (
//"fmt"
//"strings"
"unsafe"
)
//export cService
func (this *MqS) cService(cb *IService) {
defer func() {
if x := recover(); x != nil {
this.ErrorSet(x)
}
}()
this.LogC("cService",0,"1111111111111111111111\n")
(*cb).Call()
}
func (this *MqS) ServiceCreate(token string, cb IService) {
println("1. ServiceCreate ... ", cb)
t := C.CString(token)
C.gomsgque_ServiceCreate((*_Ctype_struct_MqS)(this), t,
unsafe.Pointer(&cb))
C.free(unsafe.Pointer(t))
}
func (this *MqS) ProcessEvent(timeout TIMEOUT, wait WAIT) {
this.iErrorMqToGoWithCheck(C.MqProcessEvent((*_Ctype_struct_MqS)(this),
C.MQ_TIME_T(timeout), uint32(wait)))
}
/**
* \file theLink/gomsgque/src/gomsgque.c
* \brief \$Id: gomsgque.c 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
#include "gomsgque.h"
MQ_CST sGO = "GO";
MQ_CST sUNKNOWN = "UNKNOWN";
static enum MqErrorE sServerSetup (
struct MqS * const context,
MQ_PTR const data
)
{
MqLogC(context,"sServerSetup",0,"INFO\n");
cServerSetup((int*)context->self, data);
return MqErrorStack(context);
}
void
gomsgque_ConfigSetServerSetup (
struct MqS * const context,
void *data
)
{
MqConfigSetServerSetup(context, sServerSetup, (MQ_PTR)data, NULL, NULL);
}
static enum MqErrorE sService (
struct MqS * const context,
MQ_PTR const data
)
{
MqLogC(context,"sService",0,"INFO\n");
cService((int*)context->self, data);
return MqErrorStack(context);
}
void
gomsgque_ServiceCreate (
struct MqS * const context,
MQ_TOK const token,
void *data
)
{
MqServiceCreate(context, token, sService, (MQ_PTR)data, NULL);
}
/**
* \file theLink/gomsgque/src/gomsgque.h
* \brief \$Id: gomsgque.h 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/
#include <stdlib.h>
#include "msgque.h"
#include "debug.h"
extern MQ_CST sGO;
extern MQ_CST sUNKNOWN;
void gomsgque_ConfigSetServerSetup (struct MqS * const, void *data);
void gomsgque_ServiceCreate (struct MqS * const, MQ_TOK const token,
void *data);
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5lKOAAoJEGTcPijNG3/Amm8H/jZLkOSQY0IfBRov2enJVe2G
t03M6nO9924q973oKZTdnwIFDGkM8N7wqZablCXHpi410yXie6ZtQa/JDk0v0YLB
08WDdy0K60KVAmhHObIK8Fld1Nw4DH/eobxqL9GhTJpJfONReVD+k3s4Z1iSJUSG
nkYro0SzoLW+emaZi+CTNNTVPm1+o9nG3PIzQ14jZY9npc6L+7no9UNXaUPCp6+s
d9Tq9dHoQb3hHm677DTSiEHBkPEkcpty+oObUmtyx5qjQQlfo3Ewxh11L20KlAM+
QCfI4exT/DOkAYFnKAySRfKiU3r6OhVvwTUVGXq8QJa8nKkgjLiLQ4po50ZMvH0=
=JSso
-----END PGP SIGNATURE-----
i don't think that this (the C wrapping stuff) should affect what the package
API looks like.
i think you're still trying to use embedding too much, which makes your
problem appear more complex than it is, with a very twisty flow of control.
in fact, i don't think you strictly need the Server type at all, and if you
change the IService interface so that the MqS instance is passed in,
you don't need to store it in your service objects.
it is not usual in Go to allow panics to pass package boundaries - you
should put error returns on those routines that can fail, and do explicit
error checking.
here's how your main package could look. no embedding necessary,
which makes things clearer, i think.
package main
import (
"gomsgque"
"os"
)
type SharedState struct {
incr uint32
}
type ECOI struct {
state *SharedState
}
func (e ECOI) Call(mq *MqS) {
mq.SendSTART()
mq.SendI(mq.ReadI() + e.state.incr)
mq.SendRETURN()
}
func main() {
state := &SharedState{10}
mq := gomsgque.NewMqS()
mq.ServiceCreate("ECOI", ECOI{state})
mq.ServiceCreate("Foo", Foo{state})
... more services
mq.ConfigSetName("server")
mq.ConfigSetIdent("test-server")
mq.LinkCreate(os.Args...)
mq.LogC("test", 1, "this is the log test\n")
mq.ProcessEvent(MqS_TIMEOUT_DEFAULT, MqS_WAIT_FOREVER)
}
This look good, but one restriction is also available not mentioned yet.
- -> *multiple* "Server" in one binary have to be possible.
the example shows only a *single* server solution, I already use this
style of programming for easy problems.
In addition I have a techology called "ServerOnServer"
http://nhi1.berlios.de/theLink/csmsgque/group__csmsgqueref.htm#cs_ClientServerLink
and for this scenario you need a distinct server object to separate
Server local variables.
The "ServerSetup" is required only for the multiple-server
problem, because the *first* toplevel server is responsible to
setup/create the "child" servers ...
but yes...
the single-server problem does not need a "ServerSetup"
be aware that the server technology have to be thread-safe as well.
this mean multiple toplever server in one binary have to coexist ....
but to make it short, I think I solved all possible problems
and you can code with or without distinct toplevel server object
depending on the complexity of the problem to solve.
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5mHTAAoJEGTcPijNG3/AzCQIAJlhCSPi6Uf+mMaY+D9nRxeK
VEvwrmSGQ1jMNe4Klbwys2ZEM2Ea2PQtY2UlPDp+1/tbqZqBznBlySqxyY4cq+E6
yK1Iy/Xnru3dyxov3QiAoQ74JsfjkHqhgsS8WBJqO2Bqqre1TnIN4BvUJP/1PCj5
YnEj14HgcP6r22nVX7+F98o559Ld0KFQoTxJ5IpVyCUSIqDhfD6igj118W04Y0jc
2jxm7SKIsFf7JsRy4rH+eCCQ33MSBlG6KCwZgrpEcj6Hli59gCJ5YrW3IYdD4GrO
y8vUK6DxxW7tUkJwYPqgDQo+gVZjT6ArLrG0msnRNYkkxMKQ8iowUnq3tAKwhrA=
=29h1
-----END PGP SIGNATURE-----
i think you could easily do multiple servers with the code
i proposed - just embed the other servers inside one
of the services (assuming i understand correctly what your code is doing,
which i probably don't!)
there's no reason why the separate services have to share
the same SharedState - SharedState is just a placeholder for
any state that's in common between any given set of services.
i don't see that the Server abstraction in your code gives you
anything more than setup and teardown callbacks - and those
can easily (and more directly) be done on the caller's side.
in your code, MqS is embedded directly within Server - what's
the real distinction between MqS and Server?
Hi,
this are the first performance results ...
1. C only -> should be the fastest
> ./client @ ./server
C> (client:9015:0x7f5c5560f700) [2010-11-19:19-25-38]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:9015:0x7f5c5560f700) [2010-11-19:19-25-39]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 19.29
C> (client:9015:0x7f5c5560f700) [2010-11-19:19-25-39]
[0-0-0-0x62d780-main]: end: ----------------------------------------
2. C#
> csharp.env ./client @ MONO csserver.exe
C> (client:9019:0x7f46aa809700) [2010-11-19:19-26-04]
[0-0-0-0x62d8a0-main]: start: --------------------------------------
C> (client:9019:0x7f46aa809700) [2010-11-19:19-26-05]
[0-0-0-0x62d8a0-statistics]: MqSendEND_AND_WAIT: 20.72
C> (client:9019:0x7f46aa809700) [2010-11-19:19-26-05]
[0-0-0-0x62d8a0-main]: end: ----------------------------------------
3. JAVA
> java.env ./client @ JAVA example/Server
C> (client:13460:0x7f529fba5700) [2010-11-19:19-28-47]
[0-0-0-0x62d8a0-main]: start: --------------------------------------
C> (client:13460:0x7f529fba5700) [2010-11-19:19-28-48]
[0-0-0-0x62d8a0-statistics]: MqSendEND_AND_WAIT: 22.68
C> (client:13460:0x7f529fba5700) [2010-11-19:19-28-48]
[0-0-0-0x62d8a0-main]: end: ----------------------------------------
4. GO
> ./client @ ../gomsgque/src/server
C> (client:9027:0x7f317cda1700) [2010-11-19:19-27-05]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:9027:0x7f317cda1700) [2010-11-19:19-27-06]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 23.94
C> (client:9027:0x7f317cda1700) [2010-11-19:19-27-06]
[0-0-0-0x62d780-main]: end: ----------------------------------------
I'm disappointed from GO ... probably to mutch indirection ??
This is the GO server .....
package main
import (
. "gomsgque"
"os"
)
type Server struct {
*MqS
}
func NewServer() *Server {
ret := &Server{NewMqS()}
ret.ConfigSetServerSetup(ret)
return ret
}
func (this *Server) ServerSetup() {
this.ServiceCreate("ECOI", &ECOI{this})
this.ServiceCreate("ECOU", &ECOU{this})
this.ServiceCreate("ECUL", &ECUL{this})
}
type ECOI struct { *Server }
func (this *ECOI) Call() {
this.SendSTART()
this.SendI(this.ReadI())
this.SendRETURN()
}
type ECOU struct { *Server }
func (this *ECOU) Call() {
this.SendSTART()
this.SendU(this.ReadU())
this.SendRETURN()
}
type ECUL struct { *Server }
func (this *ECUL) Call() {
this.SendSTART()
this.SendY(this.ReadY())
this.SendS(this.ReadS())
this.SendI(this.ReadI())
this.SendW(this.ReadW())
this.ReadProxy(this.Server.MqS)
this.SendRETURN()
}
func main() {
var srv = NewServer()
defer func() {
if x := recover(); x != nil {
srv.ErrorSet(x)
}
srv.Exit()
}()
srv.ConfigSetName("server")
srv.ConfigSetIdent("test-server")
srv.LinkCreate(os.Args...)
srv.LogC("test",1,"this is the log test\n")
srv.ProcessEvent(MqS_TIMEOUT_DEFAULT, MqS_WAIT_FOREVER)
}
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5sOqAAoJEGTcPijNG3/Aj5oH/R4HwdtD42NaD3hytRu65ek4
YuA+3kFKBEVDoGKpL6cId30qoFj5Vb5bCz2V0qOG9+a3nNw76UEfYNeGyjWN5Y+t
bpAmzvtcWyT5y8cad4TYVIXSQNC5OQP7yD05yabGbRVBQVqLRZk/9bzKy+o92jV9
1NzgsWTwN9aimTxYd0sQ5Cdz0yQttFBof2BQo7M691bIqQcYB3cOjRogb8BPpxAw
vM/TDgPMbvbWjOt1g0k22LkeDgrX1B2MSItGaEIrbSjtwlMb0XQar3TC39BkwVjz
Ivw77Kapp5oSDSMYW2ZUEjVQh7y7qTRcLOvT1BlJ69FtHMrXOB8RT6q3Zo95AXw=
=QLF9
-----END PGP SIGNATURE-----
Am 19.11.2010 19:45, schrieb Cory Mainwaring:
> Pure Go is usually within 50% of C. Most of the extra performance hit
> is from getting into and out of the C code. Try to get the C code
> you're wrapping to do more at a time, and you reduce that penalty.
>
> On 19 November 2010 13:36, Andreas Otto <aott...@t-online.de> wrote:
>
> ...
> type Server struct {
> *MqS
> }
> ...
> type ECUL struct { *Server }
> func (this *ECUL) Call() {
> this.SendSTART()
> this.SendY(this.ReadY())
> this.SendS(this.ReadS())
> this.SendI(this.ReadI())
> this.SendW(this.ReadW())
> this.ReadProxy(this.Server.MqS)
> this.SendRETURN()
> }
>
I think the problem is the triple pointer de-referencing in the service
from the "embedded" code
> type Server struct { *MqS }
and
> type ECUL struct { *Server }
this mean "this.SendSTART" end op with "this.Server.MqS.SendSTART..."
I don't know if GO is smart enough to do the triple de-referencing
only once and not for every "this" !!!
the current performance is a scripting-language performance ...
I expect to be on C# performance level
Skipping the "Server" type (as mentioned before) should delete one
in-direction level ....
- -> but I don't know if this would be a good idea
I need more testing for the different coding->style's of GO
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM5sh6AAoJEGTcPijNG3/AHs8H/R+jp+ox4tovTr5Tob/EPbLf
5CqJNqHd6BldNnZbuqhKraaB0H31awjPhteV1cyYCT8TXqv9HkD6jRQmToKjf5NB
6/4D/AXc9pqqH/zHBfABcdf6o+JiJbNo86GybowMqHaelxoCvNtgmubLYL5L3PGB
ZnBJAmWNftmemBuDeEmKjJJEu8+dI3gxCb09RqNoU1IQ4psSFQqe/aWKUMHFbHxt
sKMnbAuGyfvi2XHWiKqFcCeL+Lb7nlcLxi7WmPpknzxbmiZfD6c1kUp4ThgwhLsn
/m2aWTUELVcxl8TNvd/wbEYRzZ+UB06CLAZzi7BpZfJgzWQMtpBhE52p/MgWuQ8=
=lkHZ
-----END PGP SIGNATURE-----
>> type Server struct { *MqS }
> and
>> type ECUL struct { *Server }
>
> this mean "this.SendSTART" end op with "this.Server.MqS.SendSTART..."
>
> I don't know if GO is smart enough to do the triple de-referencing
> only once and not for every "this" !!!
>
Maybe you should not create a veritable linked list you have to
traverse for every method call, rather than need Go to be "smart
enough" to figure out that you aren't altering that linked list
between calls ;-). You can embed structs instead of pointers to them.
Hi,
I do more tests ...
1. Original:
func (this *Server) ServerSetup() {
this.ServiceCreate("ECUL", &ECUL{this})
}
type ECUL struct { *Server }
func (this *ECUL) Call() {
this.SendSTART()
this.SendY(this.ReadY())
this.SendS(this.ReadS())
this.SendI(this.ReadI())
this.SendW(this.ReadW())
this.ReadProxy(this.Server.MqS)
this.SendRETURN()
}
> ./client @ ../gomsgque/src/server
C> (client:7839:0x7f0667c18700) [2010-11-21:09-25-53]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:7839:0x7f0667c18700) [2010-11-21:09-25-54]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.50
C> (client:7839:0x7f0667c18700) [2010-11-21:09-25-54]
[0-0-0-0x62d780-main]: end: ----------------------------------------
2. replace this
type ECUL struct { *Server }
func (this *ECUL) Call() {
ctx := this.Server.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}
> ./client @ ../gomsgque/src/server
C> (client:7811:0x7fbb8538d700) [2010-11-21:09-24-47]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:7811:0x7fbb8538d700) [2010-11-21:09-24-48]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.47
C> (client:7811:0x7fbb8538d700) [2010-11-21:09-24-48]
[0-0-0-0x62d780-main]: end: ----------------------------------------
3. replace service de-reference
func (this *Server) ServerSetup() {
this.ServiceCreate("ECUL", (*ECUL)(this))
}
type ECUL Server
func (this *ECUL) Call() {
ctx := this.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}
> ./client @ ../gomsgque/src/server
C> (client:7783:0x7f4e07f6c700) [2010-11-21:09-23-54]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:7783:0x7f4e07f6c700) [2010-11-21:09-23-55]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.45
C> (client:7783:0x7f4e07f6c700) [2010-11-21:09-23-55]
[0-0-0-0x62d780-main]: end: ----------------------------------------
==> all three tests does not show up any performance improvement
4.
New try -> skip "C" callback and try to call "GO" callback directly from
"libmsgque"
//export gomsgque_cService
func (this *MqS) cService(cb *Service) uint32 {
defer func() {
if x := recover(); x != nil {
this.ErrorSet(x)
}
}()
(*cb).Call()
return C.MqErrorGetCode((*_Ctype_struct_MqS)(this))
}
func (this *MqS) ServiceCreate(token string, cb Service) {
t := C.CString(token)
C.gomsgque_ServiceCreate((*_Ctype_struct_MqS)(this), t,
unsafe.Pointer(&cb))
C.free(unsafe.Pointer(t))
}
void
gomsgque_ServiceCreate (
struct MqS * const context,
MQ_TOK const token,
void *data
)
{
MqServiceCreate(context, token, (MqTokenF)gomsgque_cService,
(MQ_PTR)data, NULL);
}
RESULT
> ./client @ ../gomsgque/src/server
C> (client:9683:0x7fcf9d7a7700) [2010-11-21:09-47-14]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:9683:0x7fcf9d7a7700) [2010-11-21:09-47-15]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.52
C> (client:9683:0x7fcf9d7a7700) [2010-11-21:09-47-15]
[0-0-0-0x62d780-main]: end: ----------------------------------------
- --> same result nothing help
Just to remember, we other results
!C! > ./client @ ./server
C> (client:11949:0x7fd207171700) [2010-11-21:09-50-19]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:11949:0x7fd207171700) [2010-11-21:09-50-20]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 18.35
C> (client:11949:0x7fd207171700) [2010-11-21:09-50-20]
[0-0-0-0x62d780-main]: end: ----------------------------------------
!C#! > csharp.env ./client @ MONO csserver.exe
C> (client:11953:0x7f842a2d5700) [2010-11-21:09-50-39]
[0-0-0-0x62d8a0-main]: start: --------------------------------------
C> (client:11953:0x7f842a2d5700) [2010-11-21:09-50-40]
[0-0-0-0x62d8a0-statistics]: MqSendEND_AND_WAIT: 19.60
C> (client:11953:0x7f842a2d5700) [2010-11-21:09-50-40]
[0-0-0-0x62d8a0-main]: end: ----------------------------------------
!JAVA! > java.env ./client @ JAVA example/Server
C> (client:11961:0x7f6554830700) [2010-11-21:09-51-05]
[0-0-0-0x62d8a0-main]: start: --------------------------------------
C> (client:11961:0x7f6554830700) [2010-11-21:09-51-06]
[0-0-0-0x62d8a0-statistics]: MqSendEND_AND_WAIT: 21.30
C> (client:11961:0x7f6554830700) [2010-11-21:09-51-06]
[0-0-0-0x62d8a0-main]: end: ----------------------------------------
=============================================================================
Next try embedding MqS struct and not the pointer
CODE:
package gomsgque
// for toplevel "MqS"
func NewMqS() *MqS {
this := C.MqContextCreate(0,nil)
C.MqConfigSetSelf(this, unsafe.Pointer(this))
return (*MqS)(this)
}
// for embedding "MqS"
func (this *MqS) Init() {
C.MqContextInit((*_Ctype_struct_MqS)(this), 0,nil)
C.MqConfigSetSelf((*_Ctype_struct_MqS)(this), unsafe.Pointer(this))
}
1. embedding
package main
type Server struct {
MqS
}
func NewServer() *Server {
ret := new(Server)
ret.Init()
ret.ConfigSetServerSetup(ret)
return ret
}
type ECUL Server
func (this *ECUL) Call() {
ctx := &this.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}
RESULT
> ./client @ ../gomsgque/src/server
C> (client:13868:0x7fb7aba11700) [2010-11-21:10-23-12]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:13868:0x7fb7aba11700) [2010-11-21:10-23-13]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.85
C> (client:13868:0x7fb7aba11700) [2010-11-21:10-23-13]
[0-0-0-0x62d780-main]: end: ----------------------------------------
ANALYZE: the problem is that in "C" you can do a "Pointer-cast"
if the embedded struct is the fist object and the
pointer-address of *Server is equal to *MqS
MqS *ctx = (MqS*)(server) -> the is a "O" time operation
In go this is !not! allowed -> and you end-up in something like
MqS *ctx = &(server->MqS)
- -> this is still a kind of double-de-reference problem
code: ctx := (*MqS)(this)
compile error: server.go:53: cannot convert this (type *ECUL) to type
*gomsgque.MqS
or: ctx := (*MqS)((*Server)(this))
- ->: server.go:53: cannot convert (*Server)(this) (type *Server) to type
*gomsgque.MqS
2. referencing
type Server struct {
*MqS
}
func NewServer() *Server {
ret := &Server{NewMqS()}
ret.ConfigSetServerSetup(ret)
return ret
}
type ECUL Server
func (this *ECUL) Call() {
ctx := this.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}
RESULT:
> ./client @ ../gomsgque/src/server
C> (client:13957:0x7f8c06f87700) [2010-11-21:10-25-54]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:13957:0x7f8c06f87700) [2010-11-21:10-25-55]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.62
C> (client:13957:0x7f8c06f87700) [2010-11-21:10-25-55]
[0-0-0-0x62d780-main]: end: ----------------------------------------
- -> not real a difference
It doesn't matter how to program "GO" there is a "hidden" wall at "22.*"
##########################################################
next try provide "*MqS" as interface argument
package gomsgque
type Service interface {
Call(*MqS)
}
//export gomsgque_cService
func (this *MqS) cService(cb *Service) uint32 {
defer func() {
if x := recover(); x != nil {
this.ErrorSet(x)
}
}()
(*cb).Call(this)
//return C.MqErrorGetCode((*_Ctype_struct_MqS)(this))
return this.error.code
}
package main
type ECUL Server
func (this *ECUL) Call(ctx *MqS) {
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}
RESULT:
> ./client @ ../gomsgque/src/server
C> (client:14829:0x7f7f04e1f700) [2010-11-21:10-56-23]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:14829:0x7f7f04e1f700) [2010-11-21:10-56-24]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.60
C> (client:14829:0x7f7f04e1f700) [2010-11-21:10-56-24]
[0-0-0-0x62d780-main]: end: ----------------------------------------
- -> nothing help, still the "22.*" wall
next try -> skip the "recover" part from cService
//export gomsgque_cService
func (this *MqS) cService(cb *Service) uint32 {
(*cb).Call(this)
//return C.MqErrorGetCode((*_Ctype_struct_MqS)(this))
return this.error.code
}
RESULT: The Target Is Moving !!!!!!
> ./client @ ../gomsgque/src/server
C> (client:14994:0x7fc65c08f700) [2010-11-21:10-58-29]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:14994:0x7fc65c08f700) [2010-11-21:10-58-30]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 21.87
C> (client:14994:0x7fc65c08f700) [2010-11-21:10-58-30]
[0-0-0-0x62d780-main]: end: ----------------------------------------
the problem is that I need the "rescue" part to report errors from the
server to the client and "continue" the server . without this part every
"panic" will end up in a toplevel "panic" and shutdown the server -> BAD
one problem is that
defer func() {
if x := recover(); x != nil {
this.ErrorSet(x)
}
}()
will "*always*" evaluate... not only on error -> bad technology
- -> "try ... catch" would be better
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM6PNyAAoJEGTcPijNG3/AnvMH/3CQ5sVBhY8+3gPgEm6AMj0O
eKc6ea8lqfREYJ2hWz2NCqMPUAS7JDej7SXDsqeKb5zRSkhK8ZrGJExUmt1ghDTx
ovpycNkMGb6/RQgDR9XshOy/Dpvp6D1gh0DawCyh76IERyBbLVykXZrEPBLoXKNi
8n+p47guDFDoDniaff2AizUcX0yB/qmmCUaCZxBR2ZU8F+0JtTvnjCpspBZlEhXo
cn0CsQb5yR7t2xRLNRktAHvDBQ94FJCsflKmtnqjMr1MTS5zEJNoiJWH91lphT+7
nZZGJW1TvhWRJju8gdDWHXMZH4BvDaFJ9YTgPg03JT4rH+KQSdxpPCwxwws+z/4=
=CtEp
-----END PGP SIGNATURE-----
If you're dead-set on not re-writing this MqS library in Go, then your
main bottleneck is functions that look like this:
func (this *ECUL) Call() {
ctx := &this.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}
Each one of those method calls is more expensive than you think it is.
They all have the three steps. Try re-writing it so that it's just one
call into C, with C then doing that series of function calls. It will
save you 10 conversions to C. Also, find other areas like this, where
you have a bevy of function calls that each go into C, and combine
them so there's only 1 conversion into C.
Am 21.11.2010 11:47, schrieb Cory Mainwaring:
> The performance wall isn't in the defer, it's in the Go -> C
> transition. Every C function is expensive because it has 3 steps:
> "Convert to C types", "Run C function", "Convert to Go types".
>
> If you're dead-set on not re-writing this MqS library in Go, then your
> main bottleneck is functions that look like this:
if I ANNOUNCE the availability of "gomsgque" I write a couple of lines
why I choose this approach and do not re-writing the "libmsgque" library
for every language again.
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM6P5uAAoJEGTcPijNG3/AV9YH/i80UAtpeitEWKsaNWC7qbHu
Ia/pJrtft32pvIPfnDYgpgEB12FuTvfG3qfqFYg64oMsXjknDTbJnwN61umr4Olz
w8mKMEFdTVCpfVrXYbdhBYAkjVgrBeiUDx/0gQ1UVwlmKAdAtFKDngNYfueABsju
mmoFAvgSzvte3OhsFcP/JAPDWLdJ6QQDTrGeAM/jDYu1n5O58AHnH7T/pWF85BzY
dNYopQoA/9fdmMGKumuBudTLcRadnUkXPm3M40mLxjcY/xyePwnpbFzUj9iRMyRl
jC3XWVQn4sjtbc4mbsyPEGEmIR/uzlSPJY06/pMpNzsxMNjW5kHuFaQSjWPAvvI=
=gasN
-----END PGP SIGNATURE-----
Am 21.11.2010 11:47, schrieb Cory Mainwaring:
> The performance wall isn't in the defer, it's in the Go -> C
> transition. Every C function is expensive because it has 3 steps:
> "Convert to C types", "Run C function", "Convert to Go types".
>
> If you're dead-set on not re-writing this MqS library in Go, then your
> main bottleneck is functions that look like this:
>
> func (this *ECUL) Call() {
> ctx := &this.MqS
> ctx.SendSTART()
> ctx.SendY(ctx.ReadY())
> ctx.SendS(ctx.ReadS())
> ctx.SendI(ctx.ReadI())
> ctx.SendW(ctx.ReadW())
> ctx.ReadProxy(ctx)
> ctx.SendRETURN()
> }
>
Hi,
just for understanding ...
I can write the "ECUL" code entire in "C" and just call the
toplevel "ECUL" from GO -> this will be definitely
faster. But this is not the goal of the test. The goal
is to test how expensive is the call from Go to C. for the
"other" languages I have done the same setup as in GO
above.
For me the performance is OK ... flower than expected but
faster as typical "scripting" languages.
I just wondering why C#/mono (19.*) is faster than GO (22.*)
for doing the same job?
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM6P6CAAoJEGTcPijNG3/AASsIAJs4m8+Sxrkl4unoevMPyQby
i0EBTxkzjYqXZgCOx2o0z/siVMI0Dx1JKGFr3DpESiAWgtUqeLBIr9JRXxkyZCI4
66fGAIgbCNpZRf25dZz7e49sMiUQZZrwSK2iQAMG63KHBaLe4X/MhGarqpmVs647
GyyWRZ5znM4F7OK8rUgN26gGNqAheKb9L1fBcZHg+Yl1wrPGKemTuLRNLIOAWDY2
qEPtT3Jeojc1bkPMl1GVXjA9ftu5R+ItZa8zgJ8GoJaW1oNZN+Sn6E7ExFLdvHoo
kjOlFe7HX3GX+8j4zejdeZ+5YMtO9DEpTeFKGf0o7HVvCZoS+gg0WQmFy0CZzGs=
=VF1p
-----END PGP SIGNATURE-----
Hi roger,
after additional testing I think I'll go the way you
mentioned ... splitting the "Server" type from the
"MqS" type to avoid "expensive" dependencies.
the example server looks like:
package main
import (
. "gomsgque"
"os"
)
type MyServer struct {
// add server specific data
}
func NewMyServer() *MqS {
ctx := NewMqS()
srv := new(MyServer)
ctx.ConfigSetServerSetup(srv)
ctx.ConfigSetFactory(srv)
return ctx
}
func (this *MyServer) Factory(ctx *MqS) *MqS {
return NewMyServer()
}
func (this *MyServer) ServerSetup(ctx *MqS) {
ctx.ServiceCreate("HLWO", (*MyFirstService)(this))
}
type MyFirstService MyServer
func (this *MyFirstService) Call(ctx *MqS) {
ctx.SendSTART()
ctx.SendC("Hello World")
ctx.SendRETURN()
}
func main() {
var srv = NewMyServer()
defer func() {
if x := recover(); x != nil {
srv.ErrorSet(x)
}
srv.Exit()
}()
srv.LinkCreate(os.Args...)
srv.ProcessEvent(MqS_TIMEOUT_DEFAULT, MqS_WAIT_FOREVER)
}
mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJM6lgeAAoJEGTcPijNG3/AqgMIAJuU+JiQ2oXpCmGA4aCELn7P
5lNqWMdZmZt3t0iWWgginER6MMsLyeMjSZuqBfOxudFItGdSwEZsOKoXdNr9FTQX
oVnBd6fCkZSwhHegRu4w7Vjw9HzlffBBLjlBVI+QHw4+NK19CxnuIJkE45IlSHJl
YLdRQxhbreboByZyJNYCcjNpJ9374IGRsReUhG+2CEu2Hvd00XscVRTpa7AGgcn6
GjjZT1OeSqaS/oAJdgxOsRvuHDhqkvt/YQDF4qWY+f71HrVYUbDblOhuzksvQotC
QkKfNzJrgAItnTTdmcRO61hsvhHyDdzlCvdBfrXm31MXnDwb7jpfl/1P3IblCFA=
=9bK5
-----END PGP SIGNATURE-----