参考这篇文章:

http://www.ibm.com/developerworks/cn/linux/l-cn-edntwk/

这里面使用的是 libev ,不是libevent

Nodejs就是采用libev作为底层库。

先要进行安装,找到了这篇文章:

http://www.cnblogs.com/wunaozai/p/3950249.html

  1. 搜索了很多关于如何学网络编程的博客和问答。大致都是推荐学一个网络库,至于C++网络库有那么几个,各有各的好处。
    这里就选这个代码量少了,方便入门,等有一定的基础后,再看看“学之者生,用之着死”的ace或者有可能成为C++标准网络库的boost::asio,这个都是后话了。

libev原地址国外的,访问不了。从csdn上下载了一份(link),要1分的,不过我下载过了,再下载就不用了。

拷贝到03机器上,解压。

因为libev是C写的,估计用C++的编译器也没啥用。所以看看默认的编译器行不行。

  1. ./configure --prefix=/home/work/data/installed/libev
  2. make
  3. make install
  4.  
  5. 能够看到安装信息:
  6. ----------------------------------------------------------------------
  7. Libraries have been installed in:
  8. /home/work/data/installed/libev/lib
  9.  
  10. If you ever happen to want to link against installed libraries
  11. in a given directory, LIBDIR, you must either use libtool, and
  12. specify the full pathname of the library, or use the `-LLIBDIR'
  13. flag during linking and do at least one of the following:
  14. - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
  15. during execution
  16. - add LIBDIR to the `LD_RUN_PATH' environment variable
  17. during linking
  18. - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
  19. - have your system administrator add LIBDIR to `/etc/ld.so.conf'
  20.  
  21. See any operating system documentation about shared libraries for
  22. more information, such as the ld() and ld.so() manual pages.
  23. ----------------------------------------------------------------------
  24. /bin/mkdir -p '/home/work/data/installed/libev/include'
  25. /usr/bin/install -c -m ev.h ev++.h event.h '/home/work/data/installed/libev/include'
  26. /bin/mkdir -p '/home/work/data/installed/libev/share/man/man3'
  27. /usr/bin/install -c -m ev. '/home/work/data/installed/libev/share/man/man3'
  28. make[]: Leaving directory `/home/work/data/installed/libev-4.15'

然后在代码目录/home/work/data/code/libev_demo里写了个示例程序libev_demo.c

  1. #include <stdio.h>
  2. #include <ev.h> //ev库头文件,注意这是C头文件,C++是ev++.h
  3.  
  4. //定义一个ev_TYPE 的结构体
  5. ev_io stdin_watcher; //定义一个stdin的观测者
  6. ev_timer timeout_watcher; //定义一个timeout的观测者
  7.  
  8. //所有的watcher的回调函数都有相似的特点
  9. //当stdin有可读的数据时,将会调用下面这个回调函数
  10. static void stdin_cb(EV_P_ ev_io *w, int revents) {
  11. puts("stdin ready");
  12.  
  13. //每一次调用都必须用对应的停止函数,手动的停止其watcher
  14. //应该是表示处理过了
  15. ev_io_stop(EV_A_ w);
  16. //这将导致所有嵌套执行的ev_run停止监听
  17. ev_break(EV_A_ EVBREAK_ALL);
  18.  
  19. }
  20.  
  21. //这是一个回调函数,用于定时器回调
  22. static void timeout_cb(EV_P_ ev_timer *w, int revents) {
  23. puts("timeout");
  24. //这将导致最早运行的ev_run停止监听
  25. ev_break(EV_A_ EVBREAK_ONE);
  26. }
  27.  
  28. int main(int argc, char **args) {
  29. //使用一般默认的事件循环
  30. struct ev_loop *loop = EV_DEFAULT;
  31.  
  32. //初始化一个I/O watcher,然后启动它
  33. ev_io_init(&stdin_watcher, stdin_cb, , EV_READ);
  34. ev_io_start(loop, &stdin_watcher);
  35.  
  36. //初始化一个定时器watcher,然后启动它
  37. //只有一次,没有重复的5.5秒定时
  38. ev_timer_init(&timeout_watcher, timeout_cb, 5.5, );
  39. ev_timer_start(loop, &timeout_watcher);
  40.  
  41. //这里开始loop,等待时间开始计时
  42. ev_run(loop, );
  43. return ;
  44.  
  45. }

然后写个Makefile

  1. CXX=gcc
  2.  
  3. INCPATH= \
  4. /home/work/data/installed/libev/include
  5.  
  6. DEP_LDFLAGS= \
  7. -L/home/work/data/installed/libev/lib
  8.  
  9. DEP_LDLIBS= \
  10. -lev
  11.  
  12. TARGET= libev_demo
  13.  
  14. all : $(TARGET)
  15.  
  16. libev_demo : *.c
  17. $(CXX) -o $@ $^ -I$(INCPATH) $(DEP_LDFLAGS) $(DEP_LDLIBS)
  18.  
  19. .PHONY : all clean
  20.  
  21. clean :
  22. rm -rf $(TARGET)

然后编译并运行:

  1. $ make
  2. gcc -o libev_demo libev_demo.c -I/home/work/data/installed/libev/include -L/home/work/data/installed/libev/lib -lev
  3.  
  4. $ ./libev_demo
  5. timeout
  6.  
  7. $ ./libev_demo
  8. ls
  9. stdin ready
  10. $ ls
  11. libev_demo libev_demo.c Makefile

运行程序后,在超时或者输入字符时会中断退出。并且字符会继续传递到命令行。

另外,以上是C程序,文件后缀不能是cxx。对于cxx,要用C++的头文件。

下面在相同的目录里面写了一个C++的程序 libev_demo.cxx

  1. #include <ev++.h>
  2. #include <iostream>
  3. #include <unistd.h>
  4.  
  5. using namespace std;
  6.  
  7. class IOWatcher {
  8. public:
  9. IOWatcher(int fd, unsigned int events) {
  10. m_io.set(fd, events);
  11. m_io.set<IOWatcher, &IOWatcher::CallBack>(this);
  12. m_io.start();
  13. }
  14. void CallBack(ev::io &w, int revents) {
  15. cout << "In IOWatcher::CallBack" << endl;
  16. w.stop();
  17. }
  18.  
  19. private:
  20. ev::io m_io;
  21. };
  22.  
  23. int main() {
  24. ev::default_loop loop;
  25. IOWatcher my_io(STDIN_FILENO, ev::READ);
  26. loop.run();
  27. return ;
  28. }

然后Makefile也要改一下,包括依赖的文件和所使用的编译器:

  1. #CXX=gcc
  2. CXX=/opt/compiler/gcc-4.8.2/bin/g++
  3.  
  4. INCPATH= \
  5. /home/work/data/installed/libev/include
  6.  
  7. DEP_LDFLAGS= \
  8. -L/home/work/data/installed/libev/lib
  9.  
  10. DEP_LDLIBS= \
  11. -lev -Wl,-rpath -Wl,LIBDIR
  12.  
  13. TARGET= libev_demo
  14.  
  15. all : $(TARGET)
  16.  
  17. #libev_demo : *.c
  18. libev_demo : *.cxx
  19. $(CXX) -o $@ $^ -I$(INCPATH) $(DEP_LDFLAGS) $(DEP_LDLIBS)
  20.  
  21. .PHONY : all clean
  22.  
  23. clean :
  24. rm -rf $(TARGET)

编译并运行:

  1. $ make clean
  2. rm -rf libev_demo
  3.  
  4. $ make
  5. /opt/compiler/gcc-4.8./bin/g++ -o libev_demo libev_demo.cxx -I/home/work/data/installed/libev/include
    -L/home/work/data/installed/libev/lib -lev -Wl,-rpath -Wl,LIBDIR
  6.  
  7. $ ./libev_demo
  8. ls
  9. In IOWatcher::CallBack
  10. $ ls
  11. libev_demo libev_demo.c libev_demo.cxx Makefile

可以看到,C++的程序也能够正确编译和执行。

用gcc -E选项来编译前面的C程序,可以看到预处理的,带有宏展开的程序。

  1. gcc -E libev_demo.c -I/home/work/data/installed/libev/include > tmp

然后原来的c文件,展开成了2271行的文件。

其中main函数部分:

  1. int main(int argc, char **args) {
  2.  
  3. struct ev_loop *loop = ev_default_loop ();
  4.  
  5. do { do { ((ev_watcher *)(void *)((&stdin_watcher)))->active = ((ev_watcher *)(void *)((&stdin_watcher)))->pending = ; ( (ev_watcher *)(void *)(((&stdin_watcher))))->priority = (); (((&stdin_watcher)))->cb = ((stdin_cb)); } while (); do { ((&stdin_watcher))->fd = (()); ((&stdin_watcher))->events = ((EV_READ)) | EV__IOFDSET; } while (); } while ();
  6. ev_io_start(loop, &stdin_watcher);
  7.  
  8. do { do { ((ev_watcher *)(void *)((&timeout_watcher)))->active = ((ev_watcher *)(void *)((&timeout_watcher)))->pending = ; ( (ev_watcher *)(void *)(((&timeout_watcher))))->priority = (); (((&timeout_watcher)))->cb = ((timeout_cb)); } while (); do { ((ev_watcher_time *)((&timeout_watcher)))->at = ((5.5)); ((&timeout_watcher))->repeat = (()); } while (); } while ();
  9. ev_timer_start(loop, &timeout_watcher);
  10.  
  11. ev_run(loop, );
  12. return ;
  13.  
  14. }

Libev通过一个struct ev_loop结构表示一个事件驱动的框架。

在这个框架里面通过ev_xxx结构,ev_init、ev_xxx_set、ev_xxx_start接口箱这个事件驱动的框架里面注册事件监控器,当相应的事件监控器的事件出现时,便会触发该事件监控器的处理逻辑,去处理该事件。处理完之后,这些监控器进入到下一轮的监控中。

符合一个标准的事件驱动状态的模型。

Libev 除了提供了基本的三大类事件(IO事件、定时器事件、信号事件)外还提供了周期事件、子进程事件、文件状态改变事件等多个事件,这里我们用三大基本事件写一个例子。

  1. #include <stdio.h>
  2. #include <signal.h>
  3. #include <string.h>
  4. #include <sys/unistd.h>
  5. #include <ev.h>
  6.  
  7. void io_action(struct ev_loop *main_loop, ev_io *io_w, int e) {
  8. int rst;
  9. char buf[];
  10. memset(buf, , sizeof(buf));
  11.  
  12. puts("In IO action");
  13. read(STDIN_FILENO, buf, sizeof(buf));
  14. buf[] = '\0';
  15. printf("String input: %s\n", buf);
  16. //ev_io_stop(main_loop, io_w); // 不注释的话,只会监测一遍IO输入
  17. }
  18.  
  19. void timer_action(struct ev_loop *main_loop, ev_timer *time_w, int e) {
  20. puts("In Time action");
  21. ev_timer_stop(main_loop, time_w);
  22. }
  23.  
  24. void signal_action(struct ev_loop *main_loop, ev_signal *signal_w, int e) {
  25. puts("In Signal action");
  26. ev_signal_stop(main_loop, signal_w);
  27. ev_break(main_loop, EVBREAK_ALL);
  28. }
  29.  
  30. int main(int argc, char **argv) {
  31. ev_io io_w;
  32. ev_timer timer_w;
  33. ev_signal signal_w;
  34. struct ev_loop *main_loop = ev_default_loop();
  35.  
  36. ev_init(&io_w, io_action);
  37. ev_io_set(&io_w, STDIN_FILENO, EV_READ);
  38.  
  39. ev_init(&timer_w, timer_action);
  40. // #define ev_timer_set(ev, after_, repeat_)
  41. ev_timer_set(&timer_w, , );
  42.  
  43. ev_init(&signal_w, signal_action);
  44. // Ctrl+C
  45. ev_signal_set(&signal_w, SIGINT);
  46.  
  47. ev_io_start(main_loop, &io_w);
  48. ev_timer_start(main_loop, &timer_w);
  49. ev_signal_start(main_loop, &signal_w);
  50.  
  51. ev_run(main_loop, );
  52.  
  53. }

其中主要的时间线循环如下:

  1. 使用libev的核心是事件循环,可以用 ev_default_loop ev_loop_new 函数创建循环,或者直接使用 EV_DEFAULT 宏,
  2. 区别是 ev_default_loop 创建的事件循环不是线程安全的,而 ev_loop_new 创建的事件循环不能捕捉信号和子进程的观察器。
  3. 大多数情况下,可以像下面这样使用:
  4.  
  5. if (!ev_default_loop ())
  6. fatal ("could not initialise libev, bad $LIBEV_FLAGS in environment?");
  7. 或者明确选择一个后端:
  8.  
  9. struct ev_loop *epoller = ev_loop_new (EVBACKEND_EPOLL | EVFLAG_NOENV);
  10. if (!epoller)
  11. fatal ("no epoll found here, maybe it hides under your chair");
  12. 如果需要动态分配循环的话,建议使用 ev_loop_new ev_loop_destroy
  13.  
  14. 在创建子进程后,且想要使用事件循环时,需要先在子进程中调用 ev_default_fork ev_loop_fork 来重新初始化后端的内核状态,
  15. 它们分别对应 ev_default_loop ev_loop_new 来使用。
  16.  
  17. ev_run 启动事件循环。它的第二个参数为0时,将持续运行并处理循环直到没有活动的事件观察器或者调用了 ev_break
    另外两个取值是 EVRUN_NOWAIT EVRUN_ONCE
  18.  
  19. ev_break 跳出事件循环(在全部已发生的事件处理完之后)。
    第二个参数为 EVBREAK_ONE EVBREAK_ALL 来指定跳出最内层的 ev_run 或者全部嵌套的 ev_run
  20.  
  21. ev_suspend ev_resume 用来暂停和重启事件循环,比如在程序挂起的时候。
  1. ev_runlibev的核心,他主要做了五件事情:
  2. 1.更新更改的FD事件
  3. 2.进行必要的sleep
  4. 3.backend_poll收集pendingIO事件
  5. 4.收集pendingtimer事件
  6. 5.调用所有pending的事件

以上示例程序中,如果注释掉"ev_break(main_loop, EVBREAK_ALL);",那么程序会在调用三个回调函数后才会结束(所有的ev_xxx_stop都被调用了),否则一直监听着。也就是说,只要三种事件都发生,三个ev_xxx_stop都被调用了,那么就会出了event_loop循环。

具体ev_run和ev_break的参数说明如下:

  1. void ev_run (EV_P_ int flags);
  2.  
  3. void ev_break (EV_P_ int how);
  4.  
  5. 同样我们这里比较关注flagshow这两个参数。flags有下面这几个:
  6.  
  7. :默认值。一直循环进行处理,直到外部引用计数==0或者是显示退出。
  8. EVRUN_NOWAIT:运行一次,poll时候不会等待。如果有pending事件进行处理,否则立即返回。
  9. EVRUN_ONCE:运行一次,poll时候会等待至少一个event发生,处理完成之后返回。
  10. how有下面这几个:
  11.  
  12. EVBREAK_ONE:只是退出一次ev_run这个调用。通常来说使用这个就可以了。
  13. EVBREAK_ALL:退出所有的ev_run调用。这种情况存在于ev_runpengding处理时候会递归调用。

使用libev的核心是事件循环,可以用 ev_default_loop 或 ev_loop_new 函数创建循环,或者直接使用 EV_DEFAULT 宏,区别是 ev_default_loop 创建的事件循环不是线程安全的,而 ev_loop_new 创建的事件循环不能捕捉信号和子进程的观察器。

各个观察器(watcher)

ev_io  获取标准输入

ev_timer  创建一个 x 秒之后启动的计时器

ev_periodic 创建一个小时为单位的周期定时器

  1. static void clock_cb (struct ev_loop *loop, ev_periodic *w, int revents)
  2. {
  3. // ... its now a full hour (UTC, or TAI or whatever your clock follows)
  4. }
  5.  
  6. ev_periodic hourly_tick;
  7. ev_periodic_init (&hourly_tick, clock_cb, ., ., );
  8. ev_periodic_start (loop, &hourly_tick);

  9. 或者自定义周期方式:
  10. #include <math.h>
  11.  
  12. static ev_tstamp my_scheduler_cb (ev_periodic *w, ev_tstamp now)
  13. {
  14. return now + (. - fmod (now, .));
  15. }
  16.  
  17. ev_periodic_init (&hourly_tick, clock_cb, ., ., my_scheduler_cb);
  18.  
  19. 从当前时间开始:
  1. ev_periodic_init (&hourly_tick, clock_cb, fmod (ev_now (loop), 3600.), 3600., 0);
  1. ev_periodic_start (loop, &hourly_tick);

示例代码如下:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <unistd.h>
  4. #include <ev.h>
  5.  
  6. static void periodic_callback(struct ev_loop *loop,ev_periodic * w, int revents)
  7. {
  8. printf("every 3 seconds\n");
  9. //ev_break(loop,EVBREAK_ALL);
  10. }
  11.  
  12. //ev_tstamp=double
  13. static ev_tstamp periodic_scheduler_callback(ev_periodic *w,ev_tstamp now)
  14. {
  15. return now+; //注意时间要加上个now,是一个绝对时间
  16. }
  17.  
  18. int main(int argc, char **args)
  19. {
  20. struct ev_loop * main_loop=ev_default_loop();
  21.  
  22. ev_periodic periodic_watcher;

  23. //下面这个是第3个参数为3 是一个表达式
  24. ev_init(&periodic_watcher, periodic_callback);
  25. ev_periodic_set(&periodic_watcher,,,);
  26. ev_periodic_start(main_loop,&periodic_watcher);
  27. ev_run(main_loop,);

  28. //如果时间周期计算方式,不能通过一个表达式来表示,那么可以通过一个函数来表示,放在set的第4个参数
  29. ev_init(&periodic_watcher,periodic_callback);
  30. ev_periodic_set(&periodic_watcher,,,periodic_scheduler_callback);
  31. ev_periodic_start(main_loop,&periodic_watcher);
  32. ev_run(main_loop,);

  33. //注意上下两部分是等价的,注释掉一个就可以看到相同的效果
  34. return ;
  35. }

ev_signal 在处理信号

ev_child   fork 一个新进程,给它安装一个child处理器等待进程结束。

写一个程序来实验一下。开始怎么都写不对,看了该系列的下一篇以为因为没有set。其实不是,是因为没有ev_run(main_loop, 0);(link

  1. #include <sys/types.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <signal.h>
  5. #include <string.h>
  6. #include <sys/unistd.h>
  7. #include <ev.h>
  8.  
  9. static void child_cb (EV_P_ ev_child *w, int revents)
  10. {
  11. ev_child_stop (EV_A_ w);
  12. printf ("process %d exited with status %x\n", w->rpid, w->rstatus);
  13. }
  14.  
  15. int main(int argc, char** argv) {
  16. ev_child cw;
  17. struct ev_loop *main_loop = ev_default_loop();
  18.  
  19. pid_t pid = fork ();
  20.  
  21. if (pid < ) {
  22. // error
  23. }
  24. else if (pid == )
  25. {
  26. // the forked child executes here
  27. puts("I am here sleeping");
  28. sleep(); // seconds
  29. puts("I am waking up");
  30. //exit (1);
  31. }
  32. else
  33. {
  34. puts("F am here sleeping");
  35. sleep(); // let child go first
  36. puts("F am waking up");
  37. ev_child_init (&cw, child_cb, pid, );
  38. printf("F get, child: %d\n", pid);
  39. //ev_child_set(&cw, pid, 0);
  40. //ev_child_start (EV_DEFAULT_ &cw);
  41. ev_child_start(main_loop, &cw);
  42. ev_run(main_loop, );
  43. }
  44. return ;
  45. }

其中有一些细节。如果father在child之前醒来,比如上面的程序,那么表现正常:

  1. $ ./libev_demo
  2. F am here sleeping
  3. I am here sleeping
  4. F am waking up
  5. F get, child:
  6. I am waking up
  7. process exited with status

如果child在father之前醒来,那么程序表现是:father立刻会醒,并且进行处理。

这种现象,与子进程是否调用了exit无关。而且即使子进程不sleep,直接返回,父进程的sleep也无效,直接返回。总之,只要子进程退出了,父进程就会立即进行处理。

ev_stat 文件状态观察器

示例代码如下:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. #include <ev.h>
  6.  
  7. static void stat_callback(struct ev_loop *loop,ev_stat *w, int revents)
  8. {
  9. printf("I'm here\n");
  10. if(w->attr.st_nlink)
  11. {
  12. printf("The file size %ld\n",(long)w->attr.st_size);
  13. }
  14. else
  15. {
  16. printf("No file here\n");
  17. }
  18. }
  19.  
  20. int main(int argc, char **args)
  21. {
  22. struct ev_loop *main_loop=ev_default_loop();
  23.  
  24. ev_stat stat_watcher;
  25.  
  26. ev_init(&stat_watcher,stat_callback);
  27. ev_stat_set(&stat_watcher,"/home/work/data/code/libev_demo4/tmp",);
  28. ev_stat_start(main_loop,&stat_watcher);
  29.  
  30. ev_run(main_loop,);
  31. return ;
  32. }

运行之后,在这个目录创建文件,或者删除文件,或者修改文件,都会触发到事件(虽然创建文件的触发,可能有一点延时,不清楚是不是轮询):

  1. $ ./libev_demo
  2.  
  3. I'm here
  4. The file size
  5. I'm here
  6. No file here
  7. I'm here
  8. The file size
  9. I'm here
  10. No file here
  11. I'm here
  12. The file size

可以有如下的这些属性:

  1. if(w->attr.st_nlink)
  2. {
  3. printf("The file st_dev %d\n",w->attr.st_dev);
  4. printf("The file st_ino %d\n",w->attr.st_ino);
  5. printf("The file st_mode %d\n",w->attr.st_mode);
  6. printf("The file st_nlink %d\n",w->attr.st_nlink);
  7. printf("The file st_uid %d\n",w->attr.st_uid);
  8. printf("The file st_gid %d\n",w->attr.st_gid);
  9. printf("The file st_rdev %d\n",w->attr.st_rdev);
  10. printf("The file st_size %d\n",w->attr.st_size);
  11. printf("The file st_atime %d\n",w->attr.st_atime);
  12. printf("The file st_mtime %d\n",w->attr.st_mtime);
  13. printf("The file st_ctime %d\n",w->attr.st_ctime);
  14. }
  15. else
  16. {
  17. printf("文件不存在\n");
  18. }

上面了解了几个最主要的watcher了。ev_io ev_timer ev_periodic ev_signal ev_child ev_stat,

除了上面的几个外,还有下面这几个 ev_idle ev_prepare/ev_check ev_embed ev_fork ev_cleanup ev_async . 功能如下:

  1. ev_fork(创建的进程时的观察器),
    ev_async(异步调用观察器),
    ev_cleanup(event loop退出时触发事件),
    ev_prepare(每次event loop之前事件),
    ev_check(每次event loop之后事件),
    ev_idle(每次event loop空闲触发事件).

其中ev_timer 和 ev_periodic 的区别在于 periodic是周期性的。虽然ev_timer有一个参数repeat,但是它的含义不是重复多少次,而是下一次按照多少间隔来处理,如下:

  1. ev_timer_set(&timer_w, , );
  2.  
  3. 这样的话,第一次等5秒,然后后面每次等待1秒,就会触发事件。
  4.  
  5. 而如果在事件处理函数里面调用了
  6. ev_timer_stop(main_loop, time_w);
  7.  
  8. 这样的话,就只会处理第一次的5秒,后面的1秒都不会处理了。

而ev_periodic如再上面的示例程序,可以每隔多长时间循环处理;也可以自定义时间,来进行周期性处理。

至此,原文的系列基本学习完了。更多的内容,后面再学习。(原文地址:link

(完)

【转载】使用事件模型 & libev学习的更多相关文章

  1. 轻松学习JavaScript二十七:DOM编程学习之事件模型

    在介绍事件模型之前,我们先来看什么是事件和什么是event对象. 一事件介绍 JavaScript事件是由訪问Web页面的用户引起的一系列操作,使我们有能力创建动态页面.事件是能够被 JavaScri ...

  2. [JS学习笔记]浅谈Javascript事件模型

    DOM0级事件模型 element.on[type] = function(){} 兼容性:全部支持   lay1 lay2 lay3 e.target:直接触发事件的元素[IE8及以下不支持tage ...

  3. Javascript事件模型系列(一)事件及事件的三种模型

    一.开篇 在学习javascript之初,就在网上看过不少介绍javascript事件的文章,毕竟是js基础中的基础,文章零零散散有不少,但遗憾的是没有看到比较全面的系列文章.犹记得去年这个时候,参加 ...

  4. 隐马尔科夫模型HMM学习最佳范例

    谷歌路过这个专门介绍HMM及其相关算法的主页:http://rrurl.cn/vAgKhh 里面图文并茂动感十足,写得通俗易懂,可以说是介绍HMM很好的范例了.一个名为52nlp的博主(google ...

  5. 编写高质量代码改善C#程序的157个建议[C#闭包的陷阱、委托、事件、事件模型]

    前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议38.小心闭包中的陷阱 建议39.了解委托的实质 建议40 ...

  6. [置顶] NB多项式事件模型、神经网络、SVM之函数/几何间隔——斯坦福ML公开课笔记6

    转载请注明:http://blog.csdn.net/xinzhangyanxiang/article/details/9722701 本篇笔记针对斯坦福ML公开课的第6个视频,主要内容包括朴素贝叶斯 ...

  7. ExtJS框架基础:事件模型及其常用功能

    前言 工作中用ExtJS有一段时间了,Ext丰富的UI组件大大的提高了开发B/S应用的效率.虽然近期工作中天天都用到ExtJS,但很少对ExtJS框架原理性的东西进行过深入学习,这两天花了些时间学习了 ...

  8. [转载]Deep Learning(深度学习)学习笔记整理

    转载自:http://blog.csdn.net/zouxy09/article/details/8775360 感谢原作者:zouxy09@qq.com 八.Deep learning训练过程 8. ...

  9. [转载]Android开发者必须深入学习的10个应用开源项目

    [转载]Android开发者必须深入学习的10个应用开源项目 原文地址:Android开发者必须深入学习的10个应用开源项目(http://blog.sina.com.cn/s/blog_7b8a63 ...

随机推荐

  1. python socket相关

    套接字的工作流程(基于TCP和 UDP两个协议) TCP和UDP对比 TCP(Transmission Control Protocol)可靠的.面向连接的协议(eg:打电话).传输效率低全双工通信( ...

  2. VMware Workstation 14 PRO 下安装Ubuntu 16.04 LTS教程

    一.准备好安装的VMware Workstation 14 PRO 1.VMware Workstation 14 PRO下载链接:http://rj.baidu.com/soft/detail/13 ...

  3. Learning Deconvolution Network for Semantic Segme小结

    题目:Learning Deconvolution Network for Semantic Segmentation 作者:Hyeonwoo Noh, Seunghoon Hong, Bohyung ...

  4. spring AOP详解二

    AOP实例(通过Proxy代理模式) Spring AOP使用纯java实现,不需要专门的编译过程和类装载器,它在运行期间通过代理方式向目标类织入增强代码,它更侧重于提供一种和Spring IoC容器 ...

  5. Linux Programming之MySQL

    实验环境:Ubuntu13.04 在此之前有过一段使用MySQL数据库的经历,在Windows平台下使用GUI(当时是使用HeidiSQL和Workbench来管理数据库),并且有过使用Python中 ...

  6. PHP的发展史,功能与特点

    web1.0时代:所有的代码都是在浏览器端执行的静态脚本,用户请求的也都是服务器上事先已经存在的静态网页,用户和服务器之间不能进行任何的交互!(不需要数据库的支持) web2.0时代:用户和服务器之间 ...

  7. python 缺少包

    https://pypi.python.org/pypi/pdfminer/20140328 到这里下载相应的包,再进行安装. tar  –xivf  pybloomfilter-1.0 cd  py ...

  8. setsockopt等高级使用

    参考: setsockopt函数使用http://hi.baidu.com/yelangdefendou/item/74161d0f384abd3c4ac4a316http://blog.csdn.n ...

  9. ajax提交数据服务端返回报错

    报错如下: if response.get('X-Frame-Options') is not None:AttributeError: 'str' object has no attribute ' ...

  10. bzoj 2791 [Poi2012]Rendezvous 基环森林

    题目大意 给定一个n个顶点的有向图,每个顶点有且仅有一条出边. 对于顶点i,记它的出边为(i, a[i]). 再给出q组询问,每组询问由两个顶点a.b组成,要求输出满足下面条件的x.y: 从顶点a沿着 ...