陈硕的Blog

《Muduo 网络库:现代非阻塞C++网络编程》演讲

2012年6月30日下午将在深圳做《Muduo 网络库:现代非阻塞C++网络编程》演讲,

这是PPT:

http://www.slideshare.net/chenshuo/muduo-network-library

演讲视频:

http://v.youku.com/v_show/id_XNDIyNDc5MDMy.html

http://youtu.be/YDnCAs894Bg 


活动介绍:

http://ouropensource.51qiangzuo.com/

posted on 2012-07-01 23:55 陈硕 阅读(4153) 评论(29)  编辑 收藏 引用 所属分类: muduo

评论

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-05 19:49 唐诗

看过这个代码,对其中一些设计很不感冒
例如 channel明明可以设计成虚函数接口,结果却硬是用std::function去撸

陈硕估计老是想着用function了。却忘记了虚函数的使用。
例如用boost::bind取代虚函数这篇文章。一个对象级别的函数指针当然可以取代
类级别的虚函数,问题是我需要用大炮打蚊子吗?类带一个函数指针
与每个对象都带一个函数指针,抛开别的不说,就内存都要节省一些。而且用了boost::function调试起来看到一块块模板栈是不是有想死的感觉?

这也算是学会用std::function std::bind的一些人的通病了,啥地方都去用std::function。有玩弄技巧之嫌。

说个搞笑的事情,我们原来的头自从学会用bind这个东西后,没有bind就写不出代码了……  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 08:00 陈硕

@唐诗
如果把Channel class设计成虚函数接口,那么在下面这五处用到Channel事件回调的地方,要么各自派生一个 inner DerivedChannel class,要么他们都直接继承Channel,两种做法问题都更大。
Acceptor::acceptChannel_
Connector::channel_
EventLoop::wakeupChannel_
TcpConnection::channel_
TimerQueue::timerfdChannel_

另见:muduo.chenshuo.com/2012/07/modern-c-api-in-muduo-part-1.html  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 10:19 zjh

总是没有c来的简洁  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 11:23 杨军

void EventLoop::runInLoop(const Functor& cb)
函数中,wakeup可能会被调用2次

第一次 在queueInLoop中
第二次 自己调用  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 12:09 陈硕

@杨军
谢谢,会在下一版修正。  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 13:44 唐诗

@陈硕
Channel class设计成虚函数,直接继承Channel有啥问题?  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 13:51 陈硕

@唐诗
你的意思是说:
Acceptor is-a Channel
Connector is-a Channel
EventLoop is-a Channel
TcpConnection is-a Channel
TimerQueue is-a Channel
像这样建模?
OO 中毒太深了吧?  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 15:14 唐诗

@陈硕
为什么不可以?理由?  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 15:31 陈硕

@唐诗
除了我前面给的链接里那篇文章里给的原因,
更重要的理由就是:我认为这么建模是错的。
Acceptor is-not-a Channel, Acceptor uses a Channel to get readable event notification.
Connector is-not-a Channel, Connector uses a Channel to get writable event notification.
如此等等。

在muduo里,
EPollPoller is-a Poller,
PollPoller is-a Poller.
因此这里用了虚函数。其他地方 is-a 关系不成立。

继承不是为了复用,而是为了被复用。  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 15:56 唐诗

@陈硕
更重要的理由就是:我认为这么建模是错的。
Acceptor is-not-a Channel, Acceptor uses a Channel to get readable event notification.
Connector is-not-a Channel, Connector uses a Channel to get writable event notification.

这只是文字上的理解的区别,既然可以用虚函数,那必然可以换个理解,例如:

我们可以这么理解, 把Channel改个名字EventHandler

Acceptor is a EventHandler
Connector is a EventHandler  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 16:14 陈硕

@唐诗
改成 EventHandler 一样是错的,is-a 关系必须满足 Liskov 替换原则:
凡是程序里需要用到 EventHandler 的地方,换成它的任何一个派生类都是可行的。
但是显然 Acceptor、Connector 等等不具备这种可替换性。  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 16:23 杨军

TimerQueue::getExpired函数中

assert(end == timers_.end() || now < end->first);

应该改为now<=end->first吧
或者用upper_bound代替lower_bound  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 17:03 陈硕

@杨军
不改。你写个程序测一测吧。  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 17:38 唐诗

@陈硕
Liskov 替换原则是个过于理想化的原则,实际使用中需要权衡  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 18:10 杨军

iterator lower_bound ( const key_type& x ) const;
返回一个指向大于或者等X值的第一个元素的迭代器。

返回一个指向容器中第一个大于或等于x值的元素的迭代器

参数
x
要比较的值

返回值
返回一个指向容器中第一个大于或等于x值的元素的迭代器

#include <iostream>
#include <set>
using namespace std;

int main ()
{
set<int> myset;
set<int>::iterator it,itlow,itup;

for (int i=1; i<10; i++) myset.insert(i*10); // 10 20 30 40 50 60 70 80 90

itlow=myset.lower_bound (30); // ^
itup=myset.upper_bound (60); // ^

myset.erase(itlow,itup); // 10 20 70 80 90

cout << "myset contains:";
for (it=myset.begin(); it!=myset.end(); it++)
cout << " " << *it;
cout << endl;

return 0;
}
  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 18:21 陈硕

@杨军
你认为 muduo 代码中的 UINTPTR_MAX 的作用是什么?
https://gist.github.com/3059083  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-06 18:56 杨军

喔,受教了,麻烦了啊  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-07 17:50 杨军

size_t n = connections_.erase(conn->name());
(void)n;

经常看你在返回值前面加一个void,这是为什么啊  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-07 18:05 陈硕

@杨军
你试试去掉它,然后用
BUILD_TYPE=release ./build.sh
编译。  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-08 23:11 杨军

@陈硕
了解,不过(void)n;这种类似的语句也会带来额外的代码
在C#里面,经常用2套代码
#DEBUG
#END

#RELEASE

#END

来解决,不过太繁琐了,不知道有没有更优雅的解决办法  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-08 23:54 陈硕

@杨军
> 不过(void)n;这种类似的语句也会带来额外的代码

Are you sure?  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-10 02:07 唐诗

一定要纠结学术上的Liskov 替换原则可以设计两个一模一样的接口,ConnectionEventHandler和DataEventHandler,两者成员函数完全一样,Acceptor、Connector 分别继承这两个类,这样也比到处是boost::bind要好,core掉的时候就不用看着到处的模板目瞪口呆了

不过,既然是一模一样,顺其自然到不如就共用一个接口类了  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-10 08:42 陈硕

@唐诗
ConnectionEventHandler 和 DataEventHandler 二者的成员函数当然不一样,Connector 关心的是 writable event,Acceptor 关心的是 readable event。


说到底你说因为debug的原因而影响设计,但是 boost::bind 真的有那么难调试吗?
我故意制造一个core dump,调用栈一样容易看嘛。

一眼看出 muduo::net::Channel::handleEventWithGuard 调用了 cdns::Resolver::onRead,有困难吗?

(gdb) bt
#0 cdns::Resolver::onRead (this=0x7ffff7c7ee90, sockfd=6, t=...)
at /home/schen/muduo/examples/cdns/Resolver.cc:102
#1 0x000000000041011a in boost::function1<void, muduo::Timestamp>::operator() (this=0xc32ae0,
receiveTime=<value optimized out>) at /usr/include/boost/function/function_template.hpp:1013
#2 muduo::net::Channel::handleEventWithGuard (this=0xc32ae0, receiveTime=<value optimized out>)
at /home/schen/muduo/muduo/net/Channel.cc:90
#3 0x00000000004102fb in muduo::net::Channel::handleEvent (this=0xc32ae0,
receiveTime=<value optimized out>) at /home/schen/muduo/muduo/net/Channel.cc:65
#4 0x00000000004131b5 in muduo::net::EventLoop::loop (this=0x7ffff7c7ede0)
at /home/schen/muduo/muduo/net/EventLoop.cc:122
#5 0x000000000040d5c2 in main (argc=<value optimized out>, argv=0x7ffff7c7f0a8)
at /home/schen/muduo/examples/cdns/dns.cc:51
  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-22 12:27 杨军

server_threaded_efficient
和server_threaded_highperformance
算法太精妙了,看了回味无穷啊,太牛逼了  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-24 17:39 xxf

你好,我最近想搞个网络服务器,参考了你的muduo代码,在阅读过程中,有些地方有点疑问,希望解答,谢谢。

1、epoll_wait检查到有准备好io的描述符后,在获取描述符的时候执行了:
96 channel->set_revents(events_[i].events);
修改了chanel里关注的event为epoll_wait当前检查到的event,并在后面的:
void Channel::handleEventWithGuard(Timestamp receiveTime)
直接取 revents_ 与EPOLLIN等进行比较,有个问题,如果原来某个描述同时关注In和out事件,这时客户端消息来了,可读,则因为 set_revents()的调用,以后就不会再关注out事件了,这样会导致有些数据不会写入socket?

2、 72 void TcpConnection::send(const void* data, size_t len)中:
82 string message(static_cast<const char*>(data), len);
===直接用string,如果data中含有二进制数据,如0,不是会丢失吗,而且如果这个段data很长,会发生一次数据拷贝吧?
关于send的问题,我现在希望从业务逻辑线程往某个socket写数据,我想可以直接先试着写入socket的buff,然后失败才写到connection的缓冲区中,并吧socket的epoll状态modify为也关注out,这样是否有问题呢?  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-25 14:22 xxf

@xxf
第一个问题应该是我错了,此处只是修改了应用程序中的event,而epoll中还是继续关注原先的事件。

第二个关于缓冲区的问题,如果其他某个线程x要发送数据到某个socket,应该是递交一个请求给io线程y,而不应该直接在x线程中直接send,也就是吧io操作都集中到x线程中,直觉应该是这样,否则x线程就可能因为send失败而进行其他的或者反复的io,是否还有其他理由呢?
在此类操作非常热门频繁的情况下,比如某个线程从另一个进程接受数据,然后要用io线程中的某个socket给客户端转发这个消息,如果用muduo中的send(void*, size_t len)方式,会发生大量的内存new、delete操作,是否可以考虑直接递送给connection的send_buf?  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-07-26 18:33 陈硕

@xxf
2. 直接用string,如果data中含有二进制数据,如0,不是会丢失吗,而且如果这个段data很长,会发生一次数据拷贝吧?

有'\0'也不会丢失,你试试就知道。
如果跨线程发送消息,是会有一次拷贝,在C++11里可以用 move semantic 解决。  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-08-30 14:49 bertyoung

@陈硕
非常支持博主的分享精神;
我重点关注了博主对tcp发送数据的处理;
确实wakeup会调用多次;
另外eventfd的一对read/write操作,接近300W次/s(至强E5-2650)
感觉还是有点耗;
不知是否能从程序角度尽量减少这种为发数据所做的唤醒。
该问题我考虑了几天,但结论仅仅是在tcpsocket注册了EPOLLOUT时不需要唤醒,一旦数据发送完全,移除EPOLLOUT事件,每次发数据还是需要唤醒的

  回复  更多评论   

# re: 《Muduo 网络库:现代非阻塞C++网络编程》演讲 2012-08-30 15:09 Solstice

@bertyoung
真要在乎这个,就不要跨线程发送数据。当前IO线程发送数据是不会wakeup的。  回复  更多评论   


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2013年9月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

导航

统计

常用链接

随笔分类

随笔档案

相册

搜索

最新评论

阅读排行榜

评论排行榜