mirror of
https://github.com/sogou/workflow.git
synced 2026-02-08 01:33:17 +08:00
Update timer docs.
This commit is contained in:
@@ -4,27 +4,64 @@
|
||||
|
||||
# 定时器的创建
|
||||
|
||||
同样是在WFTaskFactory类里的方法:
|
||||
WFTaskFactory类里包括四个定时相关的接口:
|
||||
~~~cpp
|
||||
using timer_callback_t = std::function<void (WFTimerTask *)>;
|
||||
|
||||
class WFTaskFactory
|
||||
{
|
||||
...
|
||||
static WFTimerTask *create_timer_task(unsigned int microseconds,
|
||||
timer_callback_t callback);
|
||||
public:
|
||||
static WFTimerTask *create_timer_task(time_t seconds, long nanoseconds,
|
||||
timer_callback_t callback);
|
||||
|
||||
static WFTimerTask *create_timer_task(const std::string& timer_name,
|
||||
time_t seconds, long nanoseconds,
|
||||
timer_callback_t callback);
|
||||
|
||||
static void cancel_by_name(const std::string& timer_name)
|
||||
{
|
||||
cancel_by_name(const std::string& timer_name, (size_t)-1);
|
||||
}
|
||||
|
||||
static void cancel_by_name(const std::string& timer_name, size_t max);
|
||||
};
|
||||
~~~
|
||||
目前我们提供两个创建定时器的工厂函数。第一个函数接收一个unsigned int型参,时间单位为微秒。
|
||||
如果用户需要更长时间或更高精度的定时,可以使用第二个函数接口。接口接受两个参数,分别为秒和纳秒。实际上,这个接口也具备更高的性能。
|
||||
定时器任务里同样有user_data域可以用来传递一些用户数据。启动方法和接入任务流的方法与其它任务没有区别。
|
||||
我们通过seconds和nanoseconds两个参数来指定一个定时器的定时时间。其中,nanoseconds的取值范围在[0,1000000000)。
|
||||
在创建定时器任务时,可以传入一个timer_name作为定时器名,用于cancel_by_name接口取消定时。
|
||||
定时器也是一种任务,因此使用方式与其它类型任务无异,同样有user_data域可以利用。
|
||||
|
||||
# 定时器的一个高级特征
|
||||
# 中断定时
|
||||
|
||||
如果在创建定时器任务时传入一个名称,那么这个定时器就可以在被提前中断。
|
||||
中断一个定时任务的方法是通过WFTaskFactory::cancel_by_name这个接口,这个接口默认情况下,会取消这个名称下的所有定时器。
|
||||
因此,我们也支持传入一个max参数,让操作最多取消max个定时器。当然,如果没有这个名称下的定时器,cancel操作不会产生任何效果。
|
||||
定时器在被创建之后就可取消,并非一定要等它被启动之后。以这个代码为例:
|
||||
~~~cpp
|
||||
#include <stdio.h>
|
||||
#include "workflow/WFTaskFactory.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
WFTimerTask *timer = WFTaskFactory::create_timer_task("test", 10000, 0, [](WFTimerTask *){
|
||||
printf("timer callback, state = %d, error = %d.\n", task->get_state(), task->get_error());
|
||||
});
|
||||
|
||||
WFTaskFactory::cancel_by_name("test");
|
||||
|
||||
timer->start();
|
||||
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
~~~
|
||||
程序会在立即打印出'timer callback, state = 1, error = 125.",因为定时器在运行之前就已经被取消了。所以,定时任务启动后立即callback,状态码为WFT_STATE_SYS_ERROR,错误码为ECANCELED。
|
||||
使用中需要注意的是,命名定时器比匿名定时器是会多出一些开销的,原因是我们需要维护查找表,会有加锁解锁等操作。如果你的定时器没有提前中断的需要,就不要在创建时传入timer_name了。
|
||||
|
||||
# 程序退出打断定时器
|
||||
|
||||
在[关于程序退出](./about-exit.md)里讲到,main函数结束或exit()被调用的时候,所有任务必须里运行到callback,并且没有新的任务被调起。
|
||||
这时就可能出现一个问题,定时器的定时周期可以非常长,并且不能主动打断(打断定时器的功能正在研发)。如果等定时器到期,程序退出需要很长时间。
|
||||
这时就可能出现一个问题,定时器的定时周期可以非常长,如果是不可中断的定时器,那么等待定时器到期,程序退出需要很长时间。
|
||||
而实现上,程序退出是可以打断定时器,让定时器回到callback的。如果定时器被程序退出打断,get_state()会得到一个WFT_STATE_ABORTED状态。
|
||||
当然如果定时器被程序退出打断,则不能再调起新的任务。
|
||||
以下这个程序,每间隔一秒抓取一个一个http页面。当所有url抓完毕,程序直接退出,不用等待timer回到callback,退出不会有延迟。
|
||||
|
||||
@@ -4,30 +4,61 @@
|
||||
|
||||
# Creating a timer
|
||||
|
||||
You can use the same method in the WFTaskFactory class to create a timer:
|
||||
|
||||
Timer interfaces in WFTaskFactory:
|
||||
~~~cpp
|
||||
using timer_callback_t = std::function<void (WFTimerTask *)>;
|
||||
|
||||
class WFTaskFactory
|
||||
{
|
||||
...
|
||||
static WFTimerTask *create_timer_task(unsigned int microseconds,
|
||||
timer_callback_t callback);
|
||||
public:
|
||||
static WFTimerTask *create_timer_task(time_t seconds, long nanoseconds,
|
||||
timer_callback_t callback);
|
||||
|
||||
static WFTimerTask *create_timer_task(const std::string& timer_name,
|
||||
time_t seconds, long nanoseconds,
|
||||
timer_callback_t callback);
|
||||
|
||||
static void cancel_by_name(const std::string& timer_name)
|
||||
{
|
||||
cancel_by_name(const std::string& timer_name, (size_t)-1);
|
||||
}
|
||||
|
||||
static void cancel_by_name(const std::string& timer_name, size_t max);
|
||||
};
|
||||
~~~
|
||||
We specify the timing time of a timer through the seconds and nanoseconds parameters. Among them, the value range of nanoseconds is [0,1000000000). When creating a timer, a timer_name can be specified. And we may interrupt a timer by calling **cancel_by_name** with this name later.
|
||||
As a standard workflow task, there is also a user\_data field in the timer task that can be used to transfer some user data. Its starting method is the same as other tasks, and the procedure for adding it into the workflow is also the same.
|
||||
|
||||
We'v got two factory functions that create timers. The first one accepts one parameter representing the duration in microseconds.
|
||||
But if timer with longer or more precise duration is required, you have to use the second function, which accepts two parameters, seconds and nanoseconds, and has better performance.
|
||||
Unless the program is terminated, the timer cannot be interrupted (**interrupting a timer by user is under development**).
|
||||
There is also a user\_data field in the timer task that can be used to transfer some user data. Its starting method is the same as other tasks, and the procedure for adding it into the workflow is also the same.
|
||||
# Canceling a timer
|
||||
|
||||
# Advanced features of a timer
|
||||
A named timer can be interrupted throught WFTaskFacotry::cancel_by_name interface, which will cancel all timers under the name by default. So we provide another cancel interface with the second argument **max** for user to cancel at most **max** timers. And of course, if no timer under the name, nothing performed.
|
||||
You can cancel a timer right after it's created, for example:
|
||||
~~~cpp
|
||||
#include <stdio.h>
|
||||
#include "workflow/WFTaskFactory.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
WFTimerTask *timer = WFTaskFactory::create_timer_task("test", 10000, 0, [](WFTimerTask *){
|
||||
printf("timer callback, state = %d, error = %d.\n", task->get_state(), task->get_error());
|
||||
});
|
||||
|
||||
WFTaskFactory::cancel_by_name("test");
|
||||
|
||||
timer->start();
|
||||
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
~~~
|
||||
This program prints 'timer callback, state = 1, error = 125.",immediately because the timer has be canceled before started, and it will run to callback soon after it's started. And the state code would be WFT_STATE_SYS_ERROR and the error code would be ECANCELED.
|
||||
By the way, create named timer when and only when you may need to cancel it, because it costs more. In other scenarios just use anonymous timer.
|
||||
|
||||
# Interrupting timer by program exit
|
||||
|
||||
In [About exit](/docs/en/about-exit.md), you learn that the condition that a main thread can safely end (calls **exit()** or return in the main function) is that all tasks have been run to the callback and no new task is started.
|
||||
Then, there may be a problem. As the duration of a timer could be long and it cannot be interrupted by users, if you wait for the timer to expire, it will take a long time for the program to exit.
|
||||
Then, there may be a problem, if you wait for the timer to expire, it will take a long time for the program to exit.
|
||||
But in practice, exiting the program can interrupt the timer safely and make it return to the callback. If the timer is interrupted by exiting the program, **get\_state()** will return a WFT\_STATE\_ABORTED state.
|
||||
Of course, if the timer is interrupted by exiting the program, no new tasks can be started.
|
||||
The following program demonstrates crawling one HTTP page at every one second. When all URLs are crawled, the program exits directly without waiting for the timer to return to the callback, and there will be no delay in exiting.
|
||||
|
||||
Reference in New Issue
Block a user