0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

定時(shí)器如何實(shí)現(xiàn)定時(shí)任務(wù)

科技綠洲 ? 來(lái)源:Linux開(kāi)發(fā)架構(gòu)之路 ? 作者:Linux開(kāi)發(fā)架構(gòu)之路 ? 2023-11-09 17:20 ? 次閱讀

1.1、單次定時(shí)任務(wù)實(shí)現(xiàn)

boost 的asio庫(kù)里有幾個(gè)定時(shí)器,老的有 deadline_timer , 還有三個(gè)可配合 C++11 的 chrono 使用的 high_resolution_timer 、 steady_timer 和 system_timer 。deadline_timer是asio早期版本提供的定時(shí)器,使用boost.date_time庫(kù)提供時(shí)間支持,deadline_timer會(huì)被逐漸淘汰。

僅僅固定時(shí)間后去執(zhí)行某任務(wù),可以使用boost中的asio庫(kù)提供了steady_timer定時(shí)器,定時(shí)器的用法也是比較簡(jiǎn)單的,基本上分三步。創(chuàng)建 io_service , 創(chuàng)建timer 并設(shè)置等待時(shí)間, 調(diào)用wait 或async_wait 等待.

其中wait是同步等待,async_wait是異步等待,需要給一個(gè)回調(diào)給它。

具體實(shí)現(xiàn)如下:

#include
#include
#include
#include

void executeMission()
{
std::cout<<"excute mission"<}

int main()
{
boost::asio::io_context io_ctx;
boost::asio::steady_timer asio_steady_timer{io_ctx,
std::chrono::seconds{3}};
asio_steady_timer.async_wait([](const boost::system::error_code &ec)
{std::cout<<"excute mission"< //asio_steady_timer.async_wait(&executeMission);
std::cout<<"start io_service"<
io_ctx.run();

return 0;
};
;});
;

1.2、執(zhí)行固定次數(shù)的定時(shí)任務(wù)

為了實(shí)現(xiàn)重復(fù)定時(shí),需要在回調(diào)函數(shù)里修改steady_timer的過(guò)期時(shí)間,因此要把steady_timer傳給回調(diào)函數(shù):

#include
#include
#include
#include
int count = 0;

void executeMission(const boost::system::error_code& e, boost::asio::steady_timer *t)
{
std::cout << "execute mission" << std::endl;
if(count < 10) {
++count;
t->expires_at(t->expiry() + boost::asio::chrono::seconds(1));
t->async_wait(boost::bind(executeMission, boost::asio::placeholders::error, t));
}
}

int main()
{
boost::asio::io_context io_ctx;
boost::asio::steady_timer t(io_ctx, boost::asio::chrono::seconds(1));
t.async_wait(boost::bind(executeMission, boost::asio::placeholders::error, &t));
io_ctx.run();
std::cout << "time: " << count << std::endl;
return 0;
}

用類封裝下:

#include
#include
#include
#include
#include
#include
#include


class printer {
private:
boost::asio::io_context io_;
boost::asio::steady_timer timer_;
int count_;
void print() {
if (count_ < 500) {
std::cout << count_ << "n";
++count_;

timer_.expires_from_now(std::chrono::milliseconds (50));
timer_.async_wait(std::bind(&printer::print, this));
}
else
{
std::cout << "Final count is " << count_ << "n";
delete this;
}
}
void run() {
timer_.expires_from_now(std::chrono::milliseconds (50));
timer_.async_wait(std::bind(&printer::print, this));
io_.run();
}
printer()
: timer_(io_),
count_(0) {

}
~printer() {

}

public:

static printer* Create(){
return new printer;
}

void start() {
std::thread t;
t = std::thread(std::mem_fn(&printer::run), this);
t.detach();
}
};
void foo()
{
printer *p = printer::Create();
p->start();
}
int main() {
foo();
std::cin.get();
return 0;
}

輸出:

....
490
491
492
493
494
495
496
497
498
499
Final count is 500

1.3、在多線程程序中處理定時(shí)回調(diào)(多線程處理多個(gè)定時(shí)任務(wù))

由一個(gè)線程來(lái)調(diào)用io_context::run()導(dǎo)致了回調(diào)函數(shù)不能夠并發(fā)的運(yùn)行。為了避免這個(gè)限制,一個(gè)直接的方法就是用線程池來(lái)調(diào)用io_context::run()。然而,為了能夠并發(fā)的處理回調(diào),還需要一種方法來(lái)同步回調(diào)對(duì)共享的非線程安全的資源的訪問(wèn)。

同一個(gè) io_context 可以同時(shí)給多個(gè) timer使下

實(shí)例1:


#include
#include
#include
#include


#include
#include
#include


class printer2 {
private:
boost::asio::steady_timer timer_;
int count_;
void print() {
if (count_ < 10) {
std::cout << count_ << "n";
++count_;

timer_.expires_from_now(std::chrono::milliseconds (500));
timer_.async_wait(std::bind(&printer2::print, this));
}
else
{
std::cout << "Final count is " << count_ << "n";
delete this;
}
}
printer2(boost::asio::io_context &io)
: timer_(io,std::chrono::milliseconds (500)),
count_(0) {
timer_.async_wait(std::bind(&printer2::print, this));

}
~printer2() {

}

public:

static printer2* Create(boost::asio::io_context &io){
return new printer2(io);
}

};

int main() {
boost::asio::io_context io;
printer2::Create(io);
printer2::Create(io);
printer2::Create(io);
printer2::Create(io);
io.run();
//boost::thread t1(boost::bind(&boost::asio::io_context::run, &io));
std::cin.get();
return 0;
}

輸出;

......
7
7
7
7
8
8
8
8
9
9
9
9
Final count is 10
Final count is 10
Final count is 10
Final count is 10

實(shí)例2:


#include
#include
#include
#include
#include
#include
#include

class Timer
{
public:
Timer(boost::asio::io_context& io_ctx, boost::asio::io_context::strand& strand_1, unsigned int timeout_, unsigned int id_): id(id_), count(0), timeout(timeout_), t(io_ctx, boost::asio::chrono::milliseconds(timeout_)), strand_(strand_1)
{
t.async_wait(boost::asio::bind_executor(strand_, boost::bind(&Timer::OnTimerCallBack, this)));
}
private:
void OnTimerCallBack()
{
if(count < 10) {
++count;
std::cout << " Id:" << id << " Count:" << count << std::endl;
t.expires_at(t.expiry() + boost::asio::chrono::milliseconds(timeout));
t.async_wait(boost::asio::bind_executor(strand_, boost::bind(&Timer::OnTimerCallBack, this)));
}
}
private:
unsigned int id;
unsigned int count;
unsigned int timeout;
boost::asio::steady_timer t;
boost::asio::io_context::strand& strand_;
};

int main()
{
boost::asio::io_context io_ctx;
boost::asio::io_context::strand strand_(io_ctx);
Timer timer1(io_ctx, strand_, 1000, 1);
Timer timer2(io_ctx, strand_, 1000, 2);
Timer timer3(io_ctx, strand_, 1000, 3);
boost::thread t1(boost::bind(&boost::asio::io_context::run, &io_ctx));
boost::thread t2(boost::bind(&boost::asio::io_context::run, &io_ctx));
t1.join();
t2.join();

return 0;
}

1.4、循環(huán)執(zhí)行定時(shí)任務(wù)

//boost::posix_time::to_simple_string函數(shù)需要這兩個(gè)頭文件
#include
#include
//使用boost.chrono代替std.chrono,
#define BOOST_ASIO_DISABLE_STD_CHRONO
#include
#include
#include
#include

class Timer
{
public:
Timer() :work_(io_), timer_(io_){}
public:
boost::thread_group thgp_;
boost::asio::io_context io_;
boost::asio::io_context::work work_;
boost::asio::steady_timer timer_;
public:
void init()
{
boost::system::error_code errCode;
thgp_.create_thread(boost::bind(&boost::asio::io_service::run, boost::ref(io_), errCode));
timer_.expires_from_now(boost::chrono::milliseconds(1000)); //設(shè)置過(guò)期時(shí)間長(zhǎng)度
timer_.async_wait(boost::bind(&Timer::excuteMission, this, boost::asio::placeholders::error));//異步等待
std::cout << "initialize:" << localTime() << std::endl;
//由Console可知, 函數(shù)立即返回了, 定時(shí)器的expires_from_now是由完成端口處理的
}
void stop()
{
timer_.cancel(); // 取消所有handler
work_.~work();
thgp_.join_all();
std::cout << "Stop:" << localTime() << std::endl;
}
static std::string localTime()
{
return boost::posix_time::to_simple_string(boost::posix_time::microsec_clock::local_time());
}

void excuteMission(const boost::system::error_code& ec)
{
std::cout<<"mission to print time:"< timer_.expires_from_now(boost::chrono::milliseconds(1000));
timer_.async_wait(boost::bind(&Timer::excuteMission, boost::ref(*this), _1));
#if 0
timer_.async_wait(boost::bind(&Timer::excuteMission, this, _1));
timer_.async_wait(boost::bind(&Timer::excuteMission, this, boost::asio::placeholders::error));
#endif
}
};

int main(int argc, char** argv)
{
Timer t;
t.init();
while(true)
{
std::cout<<"execute other mission"< boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
}
t.stop();
std::cout << "press ENTER to exit..." << std::endl;
// std::cin.sync();
return 0;
};
().c_str()<<">

2、實(shí)現(xiàn)一個(gè)定時(shí)器執(zhí)行定時(shí)任務(wù)

定時(shí)器一般支持單線程就夠了,一般使用方法見(jiàn)下面代碼。如果需要多線程怎么辦,筆者一般用一個(gè)簡(jiǎn)單的辦法:多線程的業(yè)務(wù)線程中不包含定時(shí)器管理器,單獨(dú)啟一個(gè)線程用來(lái)管理所有定時(shí)器,當(dāng)時(shí)間觸發(fā)時(shí),向業(yè)務(wù)線程投遞定時(shí)器消息即可。

2.1.最小堆實(shí)現(xiàn)

頭文件min_heap.h


#ifndef TIMERMANAGER_H
#define TIMERMANAGER_H

#include
#include
namespace MinHeap {

class TimerManager;

class Timer
{
public:
enum TimerType { ONCE, CIRCLE };

Timer(TimerManager& manager);
~Timer();

template
void Start(Fun fun, unsigned interval, TimerType timeType = CIRCLE);
void Stop();

private:
void OnTimer(unsigned long long now);

private:
friend class TimerManager;
TimerManager& manager_;
TimerType timerType_;
boost::function timerFun_;
unsigned interval_;
unsigned long long expires_;

size_t heapIndex_;
};

class TimerManager
{
public:
static unsigned long long GetCurrentMillisecs();
void DetectTimers();
private:
friend class Timer;
void AddTimer(Timer* timer);
void RemoveTimer(Timer* timer);

void UpHeap(size_t index);
void DownHeap(size_t index);
void SwapHeap(size_t, size_t index2);

private:
struct HeapEntry
{
unsigned long long time;
Timer* timer;
};
std::vector heap_;
};

template
void Timer::Start(Fun fun, unsigned interval, TimerType timeType)
{
Stop();
interval_ = interval;
timerFun_ = fun;
timerType_ = timeType;
expires_ = interval_ + TimerManager::GetCurrentMillisecs();
manager_.AddTimer(this);
}

}
#endif // TIMERMANAGER_H(void)>

源文件min_heap.cpp

#include "min_heap.h"
#define _CRT_SECURE_NO_WARNINGS
# include

namespace MinHeap {

Timer::Timer(TimerManager& manager)
: manager_(manager)
, heapIndex_(-1)
{
}

Timer::~Timer()
{
Stop();
}

void Timer::Stop()
{
if (heapIndex_ != -1)
{
manager_.RemoveTimer(this);
heapIndex_ = -1;
}
}

void Timer::OnTimer(unsigned long long now)
{
if (timerType_ == Timer::CIRCLE)
{
expires_ = interval_ + now;
manager_.AddTimer(this);
}
else
{
heapIndex_ = -1;
}
timerFun_();
}

// TimerManager
void TimerManager::AddTimer(Timer* timer)
{
timer->heapIndex_ = heap_.size();
HeapEntry entry = { timer->expires_, timer };
heap_.push_back(entry);
UpHeap(heap_.size() - 1);
}

void TimerManager::RemoveTimer(Timer* timer)
{
size_t index = timer->heapIndex_;
if (!heap_.empty() && index < heap_.size())
{
if (index == heap_.size() - 1)
{
heap_.pop_back();
}
else
{
SwapHeap(index, heap_.size() - 1);
heap_.pop_back();
size_t parent = (index - 1) / 2;
if (index > 0 && heap_[index].time < heap_[parent].time)
UpHeap(index);
else
DownHeap(index);
}
}
}

void TimerManager::DetectTimers()
{
unsigned long long now = GetCurrentMillisecs();

while (!heap_.empty() && heap_[0].time <= now)
{
Timer* timer = heap_[0].timer;
RemoveTimer(timer);
timer->OnTimer(now);
}
}

void TimerManager::UpHeap(size_t index)
{
size_t parent = (index - 1) / 2;
while (index > 0 && heap_[index].time < heap_[parent].time)
{
SwapHeap(index, parent);
index = parent;
parent = (index - 1) / 2;
}
}

void TimerManager::DownHeap(size_t index)
{
size_t child = index * 2 + 1;
while (child < heap_.size())
{
size_t minChild = (child + 1 == heap_.size() || heap_[child].time < heap_[child + 1].time)
? child : child + 1;
if (heap_[index].time < heap_[minChild].time)
break;
SwapHeap(index, minChild);
index = minChild;
child = index * 2 + 1;
}
}

void TimerManager::SwapHeap(size_t index1, size_t index2)
{
HeapEntry tmp = heap_[index1];
heap_[index1] = heap_[index2];
heap_[index2] = tmp;
heap_[index1].timer->heapIndex_ = index1;
heap_[index2].timer->heapIndex_ = index2;
}


unsigned long long TimerManager::GetCurrentMillisecs()
{
#ifdef _MSC_VER
_timeb timebuffer;
_ftime(&timebuffer);
unsigned long long ret = timebuffer.time;
ret = ret * 1000 + timebuffer.millitm;
return ret;
#else
timeval tv;
::gettimeofday(&tv, 0);
unsigned long long ret = tv.tv_sec;
return ret * 1000 + tv.tv_usec / 1000;
#endif
}

}

2.2、時(shí)間輪實(shí)現(xiàn)

頭文件timer_wheel.h

#ifndef TIMERWHEEL_H
#define TIMERWHEEL_H
#pragma once
#include
#include
#include

namespace TimerWheel{

class TimerManager;

class Timer
{
public:
enum TimerType {ONCE, CIRCLE};

Timer(TimerManager& manager);
~Timer();

template
void Start(Fun fun, unsigned interval, TimerType timeType = CIRCLE);
void Stop();

private:
void OnTimer(unsigned long long now);

private:
friend class TimerManager;

TimerManager& manager_;
TimerType timerType_;
boost::function timerFun_;
unsigned interval_;
unsigned long long expires_;

int vecIndex_;
std::list::iterator itr_;
};

class TimerManager
{
public:
TimerManager();

static unsigned long long GetCurrentMillisecs();
void DetectTimers();

private:
friend class Timer;
void AddTimer(Timer* timer);
void RemoveTimer(Timer* timer);

int Cascade(int offset, int index);

private:
typedef std::list TimeList;
std::vector tvec_;
unsigned long long checkTime_;
};

template
inline void Timer::Start(Fun fun, unsigned interval, TimerType timeType)
{
Stop();
interval_ = interval;
timerFun_ = fun;
timerType_ = timeType;
expires_ = interval_ + TimerManager::GetCurrentMillisecs();
manager_.AddTimer(this);
}
}
#endif // TIMERWHEEL_H*>*>(void)>

源文件timer_wheel.cpp

#include "timer_wheel.h"
#define _CRT_SECURE_NO_WARNINGS
# include
#define TVN_BITS 6
#define TVR_BITS 8
#define TVN_SIZE (1 << TVN_BITS)
#define TVR_SIZE (1 << TVR_BITS)
#define TVN_MASK (TVN_SIZE - 1)
#define TVR_MASK (TVR_SIZE - 1)
#define OFFSET(N) (TVR_SIZE + (N) *TVN_SIZE)
#define INDEX(V, N) ((V >> (TVR_BITS + (N) *TVN_BITS)) & TVN_MASK)

namespace TimerWheel{
Timer::Timer(TimerManager& manager)
: manager_(manager)
, vecIndex_(-1)
{
}

Timer::~Timer()
{
Stop();
}

void Timer::Stop()
{
if (vecIndex_ != -1)
{
manager_.RemoveTimer(this);
vecIndex_ = -1;
}
}

void Timer::OnTimer(unsigned long long now)
{
if (timerType_ == Timer::CIRCLE)
{
expires_ = interval_ + now;
manager_.AddTimer(this);
}
else
{
vecIndex_ = -1;
}
timerFun_();
}

// TimerManager
TimerManager::TimerManager()
{
tvec_.resize(TVR_SIZE + 4 * TVN_SIZE);
checkTime_ = GetCurrentMillisecs();
}

void TimerManager::AddTimer(Timer* timer)
{
unsigned long long expires = timer->expires_;
unsigned long long idx = expires - checkTime_;

if (idx < TVR_SIZE)
{
timer->vecIndex_ = expires & TVR_MASK;
}
else if (idx < 1 << (TVR_BITS + TVN_BITS))
{
timer->vecIndex_ = OFFSET(0) + INDEX(expires, 0);
}
else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS))
{
timer->vecIndex_ = OFFSET(1) + INDEX(expires, 1);
}
else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS))
{
timer->vecIndex_ = OFFSET(2) + INDEX(expires, 2);
}
else if ((long long) idx < 0)
{
timer->vecIndex_ = checkTime_ & TVR_MASK;
}
else
{
if (idx > 0xffffffffUL)
{
idx = 0xffffffffUL;
expires = idx + checkTime_;
}
timer->vecIndex_ = OFFSET(3) + INDEX(expires, 3);
}

TimeList& tlist = tvec_[timer->vecIndex_];
tlist.push_back(timer);
timer->itr_ = tlist.end();
--timer->itr_;
}

void TimerManager::RemoveTimer(Timer* timer)
{
TimeList& tlist = tvec_[timer->vecIndex_];
tlist.erase(timer->itr_);
}

void TimerManager::DetectTimers()
{
unsigned long long now = GetCurrentMillisecs();
while (checkTime_ <= now)
{
int index = checkTime_ & TVR_MASK;
if (!index &&
!Cascade(OFFSET(0), INDEX(checkTime_, 0)) &&
!Cascade(OFFSET(1), INDEX(checkTime_, 1)) &&
!Cascade(OFFSET(2), INDEX(checkTime_, 2)))
{
Cascade(OFFSET(3), INDEX(checkTime_, 3));
}
++checkTime_;

TimeList& tlist = tvec_[index];
TimeList temp;
temp.splice(temp.end(), tlist);
for (TimeList::iterator itr = temp.begin(); itr != temp.end(); ++itr)
{
(*itr)->OnTimer(now);
}
}
}

int TimerManager::Cascade(int offset, int index)
{
TimeList& tlist = tvec_[offset + index];
TimeList temp;
temp.splice(temp.end(), tlist);

for (TimeList::iterator itr = temp.begin(); itr != temp.end(); ++itr)
{
AddTimer(*itr);
}

return index;
}

unsigned long long TimerManager::GetCurrentMillisecs()
{
#ifdef _MSC_VER
_timeb timebuffer;
_ftime(&timebuffer);
unsigned long long ret = timebuffer.time;
ret = ret * 1000 + timebuffer.millitm;
return ret;
#else
timeval tv;
::gettimeofday(&tv, 0);
unsigned long long ret = tv.tv_sec;
return ret * 1000 + tv.tv_usec / 1000;
#endif
}
}

2.3 定時(shí)器應(yīng)用

main.cpp

#include
#include
#include
#include "timer_wheel.h"
#include "min_heap.h"
#include

void TimerHandler()
{

std::chrono::steady_clock::duration d =
std::chrono::steady_clock::now().time_since_epoch();

std::chrono::microseconds mic = std::chrono::duration_cast(d);

std::cout << "Timer:"<}

typedef void (*Function)();

int main()
{
// MinHeap::TimerManager tm;
// MinHeap::Timer t(tm);
TimerWheel::TimerManager tm;
TimerWheel::Timer t(tm);
t.Start(&TimerHandler, 1000);
while (true)
{
tm.DetectTimers();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}

std::cin.get();
return 0;
}()>

輸出:

Timer:6674738409
Timer:6675739056
Timer:6676739783
Timer:6677740959
Timer:6678746422
Timer:6679749721
Timer:6680751169
Timer:6681754799
Timer:6682754395
Timer:6683762516
^CPress to close this window...
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 定時(shí)器
    +關(guān)注

    關(guān)注

    23

    文章

    3248

    瀏覽量

    114813
  • Boost
    +關(guān)注

    關(guān)注

    5

    文章

    370

    瀏覽量

    48106
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4331

    瀏覽量

    62622
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2108

    瀏覽量

    73651
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    SpringBoot如何實(shí)現(xiàn)動(dòng)態(tài)增刪啟停定時(shí)任務(wù)

    在spring boot項(xiàng)目中,可以通過(guò) @EnableScheduling 注解和@Scheduled注解實(shí)現(xiàn)定時(shí)任務(wù),也可以通過(guò)SchedulingConfigurer接口來(lái)實(shí)現(xiàn)定時(shí)任務(wù)
    的頭像 發(fā)表于 09-24 09:49 ?2948次閱讀
    SpringBoot如何<b class='flag-5'>實(shí)現(xiàn)</b>動(dòng)態(tài)增刪啟停<b class='flag-5'>定時(shí)任務(wù)</b>

    Python定時(shí)任務(wù)實(shí)現(xiàn)方式

    調(diào)度模塊schedule實(shí)現(xiàn)定時(shí)任務(wù) 利用任務(wù)框架APScheduler實(shí)現(xiàn)定時(shí)任務(wù) Job 作業(yè) Trigger 觸發(fā)
    的頭像 發(fā)表于 10-08 15:20 ?5734次閱讀

    解析Golang定時(shí)任務(wù)庫(kù)gron設(shè)計(jì)和原理

    正巧,最近看到了 gron 這個(gè)開(kāi)源項(xiàng)目,它是用 Golang 實(shí)現(xiàn)一個(gè)并發(fā)安全的定時(shí)任務(wù)庫(kù)。實(shí)現(xiàn)非常簡(jiǎn)單精巧,代碼量也不多。今天我們就來(lái)一起結(jié)合源碼看一下,怎樣基于 Golang 的能力做出來(lái)一個(gè)【
    的頭像 發(fā)表于 12-15 13:57 ?1340次閱讀

    求一種SpringBoot定時(shí)任務(wù)動(dòng)態(tài)管理通用解決方案

    SpringBoot的定時(shí)任務(wù)的加強(qiáng)工具,實(shí)現(xiàn)對(duì)SpringBoot原生的定時(shí)任務(wù)進(jìn)行動(dòng)態(tài)管理,完全兼容原生@Scheduled注解,無(wú)需對(duì)原本的定時(shí)任務(wù)進(jìn)行修改
    的頭像 發(fā)表于 02-03 09:49 ?783次閱讀

    SpringBoot如何實(shí)現(xiàn)定時(shí)任務(wù)(上)

    SpringBoot創(chuàng)建定時(shí)任務(wù)的方式很簡(jiǎn)單,主要有兩種方式:一、基于注解的方式(@Scheduled)二、數(shù)據(jù)庫(kù)動(dòng)態(tài)配置。實(shí)際開(kāi)發(fā)中,第一種需要在代碼中寫(xiě)死表達(dá)式,如果修改起來(lái),又得重啟會(huì)顯得很麻煩;所以我們往往會(huì)采取第二種方式,可以直接從數(shù)據(jù)庫(kù)中讀取定時(shí)任務(wù)的指定執(zhí)行
    的頭像 發(fā)表于 04-07 14:51 ?1350次閱讀
    SpringBoot如何<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>定時(shí)任務(wù)</b>(上)

    Spring Boot中整合兩種定時(shí)任務(wù)的方法

    在 Spring + SpringMVC 環(huán)境中,一般來(lái)說(shuō),要實(shí)現(xiàn)定時(shí)任務(wù),我們有兩中方案,一種是使用 Spring 自帶的定時(shí)任務(wù)處理 @Scheduled 注解,另一種就是使用第
    的頭像 發(fā)表于 04-07 14:55 ?1550次閱讀
    Spring Boot中整合兩種<b class='flag-5'>定時(shí)任務(wù)</b>的方法

    在Spring Boot中如何使用定時(shí)任務(wù)

    本文介紹在 Spring Boot 中如何使用定時(shí)任務(wù),使用非常簡(jiǎn)單,就不做過(guò)多說(shuō)明了。
    的頭像 發(fā)表于 04-12 10:56 ?975次閱讀

    如何動(dòng)態(tài)添加修改刪除定時(shí)任務(wù)?

    如何動(dòng)態(tài)添加修改刪除定時(shí)任務(wù)?那么我們一起看看具體怎么實(shí)現(xiàn),先看下本節(jié)大綱: (1)思路說(shuō)明; (2)代碼解析; (3)修改定時(shí)任務(wù)執(zhí)行周期特別說(shuō)明;
    的頭像 發(fā)表于 04-12 11:06 ?1083次閱讀

    定時(shí)器作用及實(shí)現(xiàn)定時(shí)器數(shù)據(jù)結(jié)構(gòu)選取介紹1

    定時(shí)器在各種場(chǎng)景都需要用到,比如游戲的Buff實(shí)現(xiàn),Redis中的過(guò)期任務(wù),Linux中的定時(shí)任務(wù)等等。顧名思義,定時(shí)器的主要用途是執(zhí)行
    的頭像 發(fā)表于 04-21 15:20 ?1203次閱讀
    <b class='flag-5'>定時(shí)器</b>作用及<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>定時(shí)器</b>數(shù)據(jù)結(jié)構(gòu)選取介紹1

    定時(shí)器作用及實(shí)現(xiàn)定時(shí)器數(shù)據(jù)結(jié)構(gòu)選取介紹2

    定時(shí)器在各種場(chǎng)景都需要用到,比如游戲的Buff實(shí)現(xiàn),Redis中的過(guò)期任務(wù),Linux中的定時(shí)任務(wù)等等。顧名思義,定時(shí)器的主要用途是執(zhí)行
    的頭像 發(fā)表于 04-21 15:20 ?1197次閱讀
    <b class='flag-5'>定時(shí)器</b>作用及<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>定時(shí)器</b>數(shù)據(jù)結(jié)構(gòu)選取介紹2

    Linux如何使用cron進(jìn)行定時(shí)任務(wù)的操作

    按計(jì)劃執(zhí)行命令對(duì)于計(jì)算機(jī)來(lái)說(shuō)非常重要,因?yàn)榧偃缥矣H自去執(zhí)行一些任務(wù)的話,可能會(huì)因?yàn)槎喾矫嬉蛩夭荒馨磿r(shí)執(zhí)行,所以定時(shí)任務(wù)就顯得非常重要了! cron就是一個(gè)能夠執(zhí)行定時(shí)任務(wù)的命令,其實(shí)該命令本身不難,下面小編帶您詳細(xì)了解!
    的頭像 發(fā)表于 05-12 16:27 ?2061次閱讀

    python定時(shí)任務(wù)實(shí)踐

    由于程序需求,監(jiān)測(cè)配置變化需要設(shè)置定時(shí)任務(wù),每分鐘執(zhí)行一次,對(duì)任務(wù)持久化要求不高,不需要時(shí)可以關(guān)閉定時(shí)任務(wù)
    的頭像 發(fā)表于 05-20 17:53 ?977次閱讀
    python<b class='flag-5'>定時(shí)任務(wù)</b>實(shí)踐

    定時(shí)器設(shè)計(jì)實(shí)現(xiàn)

    由于目前C++標(biāo)準(zhǔn)中沒(méi)有現(xiàn)成的定時(shí)器,本設(shè)計(jì)使用C++11相關(guān)語(yǔ)法并進(jìn)行封裝。 本定時(shí)器包含一個(gè)TimerManager類用于創(chuàng)建定時(shí)器和進(jìn)行定時(shí)任務(wù)管理,TimerManager會(huì)創(chuàng)
    的頭像 發(fā)表于 11-08 16:50 ?608次閱讀

    linux定時(shí)任務(wù)的用法總結(jié)

    習(xí)慣了使用 windows 的計(jì)劃任務(wù),使用 linux 中的 crontab 管理定時(shí)任務(wù)時(shí)很不適應(yīng)。
    的頭像 發(fā)表于 08-14 18:16 ?851次閱讀
    linux<b class='flag-5'>定時(shí)任務(wù)</b>的用法總結(jié)

    定時(shí)器技術(shù):Air780E如何革新定時(shí)任務(wù)管理?

    今天講的是關(guān)于Air780E如何革新定時(shí)任務(wù)管理的內(nèi)容,希望大家有所收獲。
    的頭像 發(fā)表于 11-07 13:50 ?236次閱讀
    <b class='flag-5'>定時(shí)器</b>技術(shù):Air780E如何革新<b class='flag-5'>定時(shí)任務(wù)</b>管理?