Hi thereļ¼ Im new Goer and confused by the netpoll() function.
Heres the thing. When I start a Httpserver like this
http.ListenAndServe("127.0.0.1:9988",nil)
as far as I concerned, there should be a gorouting or thread or something else do the epoll things to check the socket events. Cause Im testing on MAC, the related runtime code is in "netpoll_kqueue.go". This func is called by the sysmon(). In order to debug, I add some "println" to print out the related information.
The println is in
netpoll_kqueue.go:
func netpoll(block bool) *g {
if kq == -1 {
return nil
}
var tp *timespec
var ts timespec
if !block {
tp = &ts
}
var events [64]keventt
retry:
n := kevent(kq, nil, 0, &events[0], int32(len(events)), tp)
println("===============")
if n < 0 {
if n != -_EINTR {
println("runtime: kevent on fd", kq, "failed with", -n)
throw("runtime: netpoll failed")
}
goto retry
}
and
proc.go.sysmon()
asmcgocall(*cgo_yield, nil)
}
// poll network if not polled for more than 10ms
lastpoll := int64(atomic.Load64(&sched.lastpoll))
now := nanotime()
println("+++++++++++++++++++++")
if netpollinited() && lastpoll != 0 && lastpoll+10*1000*1000 < now {
atomic.Cas64(&sched.lastpoll, uint64(lastpoll), uint64(now))
gp := netpoll(false) // non-blocking - returns list of goroutines
if gp != nil {
// Need to decrement number of idle locked M's
// (pretending that one more is running) before i
As mentioned before, as far as I concerned, the netpoll() function should been called frequently. However, both "======" and "++++++" are printed only once. And, only when I send a request, the "======" and "++++" are printed. It confused me a lot, according to the scenario, if the netpoll() is not the function to call system epoll and sysmon() is not the function to raise netpoll() then who do the job?
Appreciate your help
Related
Hi here is the code where I make util called as collector
import (
"context"
"errors"
"sync"
"time"
)
type Collector struct {
keyValMap *sync.Map
}
func (c *Collector) LoadOrWait(key any) (retValue any, availability int, err error) {
value, status := c.getStatusAndValue(key)
switch status {
case 0:
return nil, 0, nil
case 1:
return value, 1, nil
case 2:
ctxWithTimeout, _ := context.WithTimeout(context.Background(), 5 * time.Second)
for {
select {
case <-ctxWithTimeout.Done():
return nil, 0, errRequestTimeout
default:
value, resourceStatus := c.getStatusAndValue(key)
if resourceStatus == 1 {
return value, 1, nil
}
time.Sleep(50 * time.Millisecond)
}
}
}
return nil, 0, errRequestTimeout
}
// Store ...
func (c *Collector) Store(key any, value any) {
c.keyValMap.Store(key, value)
}
func (c *Collector) getStatusAndValue(key any) (retValue any, availability int) {
var empty any
result, loaded := c.keyValMap.LoadOrStore(key, empty)
if loaded && result != empty {
return result, 1
}
if loaded && result == empty {
return empty, 2
}
return nil, 0
}
So the purpose of this util is to act as a cache where similar value is only loaded once but read many times. However when an object of Collector is passed to multiple goroutines I am facing increase in gorotines and ram usage whenever multiple goroutines are trying to use collector cache. Could someone explain if this usage of sync Map is correct. If yes then what might be the cause high number of goroutines / high ram usage
For sure, you're facing possible memory leaks due to not calling the cancel func of the newly created ctxWithTimeout context. In order to fix this change the line to these:
ctxWithTimeout, cancelFunc := context.WithTimeout(context.Background(), requestTimeout)
defer cancelFunc()
Thanks to this, you're always sure to clean up all the resources allocated once the context expires. This should address the issue of the leaks.
About the usage of sync.Map seems good to me.
Let me know if this solves your issue or if there is something else to address, thanks!
You show the code on the reader side of things, but not the code which does the request (and calls .Store(key, value)).
With the code you display :
the first goroutine which tries to access a given key will store your empty value in the map (when executing c.keyValMap.LoadOrStore(key, empty)),
so all goroutines that will come afterwards querying for the same key will enter the "query with timeout" loop -- even if the action that actually runs the request and stores its result in the cache isn't executed.
[after your update]
The code for your collector alone seems to be ok regarding resource consumption : I don't see deadlocks or multiplication of goroutines in that code alone.
You should probably look at other places in your code.
Also, if this structure only grows and never shrinks, it is bound to consume more memory. Do audit your program to evaluate how many different keys can live together in your cache and how much memory the cached values can occupy.
I am writing a Kubernetes operator and dealing with a peculiar situation of handling long-running tasks from the reconcile loop.
I have the following situation:
func (r *ProvMyAppReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
// _ = context.Background()
_ = r.Log.WithValues("Instance.Namespace", req.NamespacedName)
// your logic here
var i int32
var j int32
var yappMyAppSpex myAppingv1alpha1.MyAppSpec
var result *ctrl.Result
var msg string
var requeueFlag bool
runFlag = false
<<<<< Instance prov logic>>>
// =============================== Check Deletion TimeStamp========
// Check if the MyAppOMyApp instance is marked to be deleted, which is
// // indicated by the deletion timestamp being set.
// <<<<<<<Deleteion and finalizer logic is here>>>>>>>>
// ================================ MyApp Setup ===================
if len(instance.Spec.MyApp) > 0 {
for i = 0; i < int32(len(instance.Spec.MyApp)); i++ {
yappMyAppSpex = instance.Spec.MyApp[i]
if !yappMyAppSpex.setRemove {
result, err = r.provisionStatefulSet(instance, prepareStatefulSetForMyApp(instance, yappMyAppSpex), "TYPE=TELEAPP")
if err != nil {
return *result, err
} else {
_, err = r.addMyApp(yappMyAppSpex.Name) <<< This takes lot of time and if I do any operation on a CR resource , it is not cptured by K8s as operator is busy in running this job in foreground.>>>>
if err != nil {
requeueFlag = true
}
}
}
}
}
if runFlag {
return ctrl.Result{Requeue: true, RequeueAfter: 30 * time.Second}, nil
}
return ctrl.Result{}, nil
}
I am trying to understand what is the best way to handle the above situation? Do I need to use channels and run them in the background? The main issue here is that I have to run some configuration which is taking a lot of time and causing the K8s operator not to handle other updates that are done on CR.
The first thing I would recommend is making good use of the resource status. It's important that consumers of the operator know that the operator has acknowledged the changes and is acting on it.
Then, I would recommend revisiting the API definitions - is this the right API to be using? i.e. can you split this up into more than one controller (or API)?
A simple example: in a restaurant it's not a good idea if the cook is also the waiter because you want customers to know they are being taken care of but cooking could take a long time. It's better for customers to have a waiter that takes the order, marks the order status accordingly, and then hands it to the cook(s) to execute on (this could be another API only used between cook and waiter).
In your example above you could add an API for a single app instance. The main controller would only be responsible for applying that API for each of the instances declared in the top level API (which doesn't take long). The worker controller would respond to the creation of that single-app-instance API and execute on it. This still would take time for the worker but visibility and UX would improve.
In C and similar languages the following shortcuts can be applied to detect an error and stop on first non-zero result
(void)(result = dosomething() ||
result = dosomething() ||
result = dosomething()
)
if (result == 0 && ...
In golang, I can't seem to do that.
For example:
if result = dosomething() ||
result = dosomething(); result < 0 {
fmt.Printf("Error occurred\n");
}
C is able to treat integers as a boolean expression when checking for non-zero.
for example I can write
if (result = dosomething() || ... )
Instead of
if ( (result = dosomething()) == 0 || ... )
But in go, you can't do that.
I thought I could write:
if result = dosomething() == 0 ||
result = dosomething() == 0; result < 0 {
fmt.Printf("Error occurred\n");
}
But I get an error.
syntax error: result = dosomething() || result used as value
There has to be a way of chaining these together. Or in the style of
javascript promises could a dosomething().doSomething.doSomething.error() approach be possible?
Any creative solutions to this problem? I'm really just wanting to avoid
lots of repetitive code where I want to do a whole bunch of things, but if there is an error at any point stop. Because the error handling logic for each is exactly the same.
See Errors are values on The Go Blog. This article, written by Rob Pike, has an interesting and powerful method of handling errors in a group of functions that works very well.
I have used this technique before several times, and it really works.
For reference, the code used for this technique looks like this (copied from the article):
// Helper type
type errWriter struct {
w io.Writer
err error
}
func (ew *errWriter) write(buf []byte) {
if ew.err != nil {
return
}
_, ew.err = ew.w.Write(buf)
}
//Usage:
ew := &errWriter{w: fd}
ew.write(p0[a:b])
ew.write(p1[c:d])
ew.write(p2[e:f])
// and so on
if ew.err != nil {
return ew.err
}
You could use a slice and a for loop.
https://play.golang.org/p/NJaCliBydA
s := []func() error{do1,do2,do3,do4}
for i := range s {
if err := s[i](); err != nil {
return err
}
}
return nil
Really though, you probably SHOULD follow the examples in the other answer as they come directly from documentation.
Consider the following example program which is primitive stack implementation in Go:
package main
import "fmt"
import "errors"
const MAX_SIZE = 10
var a [10]int
var top int = -1
func main() {
printStack()
push(1)
printStack()
push(23)
printStack()
pop()
push(2)
push(24)
push(56)
push(87)
push(97)
push(47)
push(37)
push(31)
push(69)
printStack()
push(75)
println("Top element is", getTop())
}
func push(x int) (int, error) {
if top >= (MAX_SIZE - 1) {
return 0, errors.New("Error: Prevented Stackoverflow. Stack full")
}
top += 1
a[top] = x
return 0, nil
}
func pop() {
top -= 1
}
func getTop() int {
return a[top]
}
func printStack() {
fmt.Println(top+1, "Stack: ", a, "Top", top)
}
Now, I read Error handling and Go & it seems the above way of returning multiple values is the way to handle errors in go.
But what I don't understand is that does do gophers check of errors on every statement? Coming from other languages this concept it bit hard for me to grok. So the question is
What is the idiomatic way of handling errors in above problem?
Is considered a bad practice if I don't check for errors? if yes, then I am supposed to check the output of push() everytime I call it?
Basically what I want to know if how would a experienced gopher do error handling in the above program?
Play URL: https://play.golang.org/p/_AnZLvY-28
[Update]
Added a real-world program where I fetch data from database & output to json. http://play.golang.org/p/dDApCYprjU
Yes, the idiomatic way to produce errors is to return multiple values. The idiomatic way to handle errors is this:
val, err := myFunc()
if err != nil {
// do something with err
}
// do something with val
At the end of the day it's a judgement call, but it's almost always good practice to handle errors. The code you're writing is also a bit unusual, you normally don't have 10 calls to the same function back-to-back, so the verbose error handling you'd have to do is more a result of the original code. For instance, you could use a loop:
for _, num := range []int{2, 24, 56, 87, 97, 47, 37, 31, 69} {
_, err := push(num)
if err != nil {
panic(err)
}
}
You have some other things that are more problematic than not handling the push errors though. One minor thing is there is no reason for push to always return 0, why not only have it return an error, instead of an int and an error? The bigger problem is that pop keeps decrementing top, and getTop just accesses a[top], so you can easily get a runtime panic if top becomes negative from having popped too much. You probably want some error handling or other safeguards in your pop and getTop functions.
This is a standard way of handling the errors in go-lang. There are two options that can follow after an error took place.
1.log the error and entirely quit the program
log the error and do some relevant task
Option one example :
func funcX() {
rtnval, err := funcY()
if err != nil {
fmt.Println("error: ", err)
os.Exit(1)
}
//rtnval
}
I'm working on a giant dictionary of words -> language, the data for which I have, but what I need is to have one thread running a daemon, written in Go, which keeps all of this in memory (yes, I have that much memory too) and is "callable" by other Go apps.
I'm sure this is a standard type of thing to do, but to be honest I've never attempted such a thing before and am not familiar enough to know where to find information on how to do this.
Having it run as a daemon is easy. My problem is what is an efficient way of calling this app from another Go app, which will need to be done many millions of times.
I'm thinking something along the lines of:
connection, err := InitateConnectionToApp()
for _, someword := range mysliceofstrings {
languageofword := connection.FindIt(someword)
}
Then the daemon somehow receives this request, looks up the value in its map and delivers it back.
I hope that makes sense. I have tried looking on Google but there is nothing I can find specific to Go.
If anyone can tell me where to start that would be great.
You could use RPC Go's standard Remote Procedure Call package.
Just Expose your api and then create a client to invoke the method remotely.
Simple example copy pasted from the docs:
package server
type Args struct {
A, B int
}
type Quotient struct {
Quo, Rem int
}
type Arith int
func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
func (t *Arith) Divide(args *Args, quo *Quotient) error {
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
func main() {
arith := new(Arith)
rpc.Register(arith)
rpc.HandleHTTP()
l, e := net.Listen("tcp", ":1234")
if e != nil {
log.Fatal("listen error:", e)
}
go http.Serve(l, nil)
}