Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question]: 异步 API 简化问题 #489

Open
3 tasks done
someview opened this issue Jul 24, 2023 · 5 comments
Open
3 tasks done

[Question]: 异步 API 简化问题 #489

someview opened this issue Jul 24, 2023 · 5 comments
Labels
help wanted Extra attention is needed question Further information is requested waiting for response waiting for the response from commenter
Milestone

Comments

@someview
Copy link

Actions I've taken before I'm here

  • I've thoroughly read the documentations about this problem but still have no answer.
  • I've searched the Github Issues/Discussions but didn't find any similar problems that have been solved.
  • I've searched the internet for this problem but didn't find anything helpful.

Questions with details

AsyncWritev([][]byte,cb)error 方法返回的error和cb的执行是否是互斥

err:=conn.AsyncWritev([][]byte,func(_ gnet,Conn,err error)error) 

如果AsyncWritev返回错误,是否内部的回调函数一定不会执行,如果asyncWritev不返回错误,内部的回调函数一定执行?

Code snippets (optional)

No response

@someview someview added help wanted Extra attention is needed question Further information is requested labels Jul 24, 2023
@panjf2000
Copy link
Owner

panjf2000 commented Jul 26, 2023

AsyncXX 函数和回调函数返回的 error 通常是系统调用的错误,系统调用报错的概率极小,可以认为这些函数返回的错误永远是 error == nil,但理论上还是有可能 err != nil,判断一下就行。

如果AsyncWritev返回错误,是否内部的回调函数一定不会执行,如果asyncWritev不返回错误,内部的回调函数一定执行?

没有必然关系,不能依赖这个逻辑关系。

@panjf2000 panjf2000 added the waiting for response waiting for the response from commenter label Jul 26, 2023
@someview
Copy link
Author

someview commented Jul 28, 2023

AsyncXX 函数和回调函数返回的 error 通常是系统调用的错误,系统调用报错的概率极小,可以认为这些函数返回的错误永远是 error == nil,但理论上还是有可能 err != nil,判断一下就行。

如果AsyncWritev返回错误,是否内部的回调函数一定不会执行,如果asyncWritev不返回错误,内部的回调函数一定执行?

没有必然关系,不能依赖这个逻辑关系。

这里的api设计令人很困惑,令人难以理解:

func (c *conn) AsyncWrite(buf []byte, callback AsyncCallback) error {
	if c.isDatagram {
		defer func() {
			if callback != nil {
				_ = callback(nil, nil)
			}
		}()
		return c.sendTo(buf)
	}
	return c.loop.poller.Trigger(c.asyncWrite, &asyncWriteHook{callback, buf})
}

func (c *conn) AsyncWritev(bs [][]byte, callback AsyncCallback) error {
	if c.isDatagram {
		return gerrors.ErrUnsupportedOp
	}
	return c.loop.poller.Trigger(c.asyncWritev, &asyncWritevHook{callback, bs})
}
type AsyncCallback func(c Conn, err error) error

callback里面的conn参数也没存在的必要,因为调用cb的地方必然能获取conn

按照通常的想法,api这样就足够了:

type cb func(err error)
Write(payload []byte)error
AsyncWrite(payload []byte,cb)

这样在多个地方返回错误显得凌乱,不清楚如果如下改动会有什么问题:

type AsyncCallback func(err error) 
func (c *conn) AsyncWritev(bs [][]byte, callback AsyncCallback) error {
	if c.isDatagram {
		return  callback(gerrors.ErrUnsupportedOp)
	}
	return c.loop.poller.Trigger(c.asyncWritev, &asyncWritevHook{callback, bs})
}
func (p *Poller) Trigger(fn queue.TaskFunc, cb AsyncCallback) {
    if atomic.CompareAndSwapInt32(&p.wakeupCall, 0, 1) {
		if _, err = unix.Write(p.efd, b); err == unix.EAGAIN {
			err = nil
		}
               return cb(err)
	}
	task := queue.GetTask()
	task.Run, task.Arg = fn, arg
	p.asyncTaskQueue.Enqueue(task)
}

即使是同步的错误,也在异步的回调里面返回错误,这样错误处理的形式比较统一.
当前遇到的问题是,为了减少内存分配,用pool来分配asycwritev分配的对象,然后这个异步的方法,内部cb不一定会执行,并且外部的err不为nil的时候内部的cb也可能执行,无法确定pool分配的对象的返回时机.

我认为还是接口设计的问题,err同步的的时候直接返回,异步的时候通过cb的参数返回

@panjf2000
Copy link
Owner

当前遇到的问题是,为了减少内存分配,用pool来分配asycwritev分配的对象,然后这个异步的方法,内部cb不一定会执行,并且外部的err不为nil的时候内部的cb也可能执行,无法确定pool分配的对象的返回时机.

抱歉,之前太忙忘了回复了,事实上你可以不用纠结这种分配回收的时机问题,一开始引入 callback 就是为了这种场景,你可以直接在 callback 里回收资源。事实上,callback 理论上是永远都会执行的,否则的话,那就是很严重的 bug。

@panjf2000
Copy link
Owner

panjf2000 commented Aug 18, 2023

我认为还是接口设计的问题,err同步的的时候直接返回,异步的时候通过cb的参数返回

至于说 API 简化的问题,因为现在已经发布了 v2 版本了,API 变更这种属于 breaking changes,只能放到下一个 major 版本里考虑了。

不过至于异步 API 是否要同步返回 error 的问题,这里我还是认为需要返回,因为这个 error 它就是可能发生的同步的错误,是提交任务是否完全成功的反馈,而通过 callback 返回的 error 实际上是异步代码真正执行过程中发生的错误。这两种 error 还是解耦一下比较好。

@panjf2000 panjf2000 modified the milestones: Long term, v3 Aug 18, 2023
@panjf2000 panjf2000 changed the title [Question]: AsyncWritev([][]byte,cb)error 方法返回的error和cb的执行是否是互斥 [Question]: AsyncWritev([][]byte,cb) error 简化问题 Aug 18, 2023
@panjf2000 panjf2000 changed the title [Question]: AsyncWritev([][]byte,cb) error 简化问题 [Question]: 异步 API 简化问题 Aug 18, 2023
@someview
Copy link
Author

我认为还是接口设计的问题,err同步的的时候直接返回,异步的时候通过cb的参数返回

至于说 API 简化的问题,因为现在已经发布了 v2 版本了,API 变更这种属于 breaking changes,只能放到下一个 major 版本里考虑了。

不过至于异步 API 是否要同步返回 error 的问题,这里我还是认为需要返回,因为这个 error 它就是可能发生的同步的错误,是提交任务是否完全成功的反馈,而通过 callback 返回的 error 实际上是异步代码真正执行过程中发生的错误。这两种 error 还是解耦一下比较好。

这种返回方式是很迷惑的行为啊,就像我上面提的问题一样。

  1. error本身足以表示出来这个是同步错误还是异步错误
  2. 如果是func submit(task)error这样的错误,这个同步错误是能否提交任务的时候报的错,但是在实践的过程中,就可能变成这样:
asyncTask(){
   syncOp1();
   asyncOp();
   syncOp2();
}

这是很让人迷惑的.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed question Further information is requested waiting for response waiting for the response from commenter
Projects
None yet
Development

No branches or pull requests

2 participants