1. 程式人生 > >golang 實現延遲訊息原理與方法

golang 實現延遲訊息原理與方法

package main;

import (
	"time"
	"errors"
	"fmt"
)

//延遲訊息
type DelayMessage struct {
	//當前下標
	curIndex int;
	//環形槽
	slots [3600]map[string]*Task;
	//關閉
	closed chan bool;
	//任務關閉
	taskClose chan bool;
	//時間關閉
	timeClose chan bool;
	//啟動時間
	startTime time.Time;
}

//執行的任務函式
type TaskFunc func(args ...interface{});

//任務
type Task struct {
	//迴圈次數
	cycleNum int;
	//執行的函式
	exec   TaskFunc;
	params []interface{};
}

//建立一個延遲訊息
func NewDelayMessage() *DelayMessage {
	dm := &DelayMessage{
		curIndex:  0,
		closed:    make(chan bool),
		taskClose: make(chan bool),
		timeClose: make(chan bool),
		startTime: time.Now(),
	};
	for i := 0; i < 3600; i++ {
		dm.slots[i] = make(map[string]*Task);
	}
	return dm;
}

//啟動延遲訊息
func (dm *DelayMessage) Start() {
	go dm.taskLoop();
	go dm.timeLoop();
	select {
	case <-dm.closed:
		{
			dm.taskClose <- true;
			dm.timeClose <- true;
			break;
		}
	};
}

//關閉延遲訊息
func (dm *DelayMessage) Close() {
	dm.closed <- true;
}

//處理每1秒的任務
func (dm *DelayMessage) taskLoop() {
	defer func() {
		fmt.Println("taskLoop exit");
	}();
	for {
		select {
		case <-dm.taskClose:
			{
				return;
			}
		default:
			{
				//取出當前的槽的任務
				tasks := dm.slots[dm.curIndex];
				if len(tasks) > 0 {
					//遍歷任務,判斷任務迴圈次數等於0,則執行任務
					//否則任務迴圈次數減1
					for k, v := range tasks {
						if v.cycleNum == 0 {
							go v.exec(v.params...);
							//刪除執行過的任務
							delete(tasks, k);
						} else {
							v.cycleNum--;
						}
					}
				}
			}
		}
	}
}

//處理每1秒移動下標
func (dm *DelayMessage) timeLoop() {
	defer func() {
		fmt.Println("timeLoop exit");
	}();
	tick := time.NewTicker(time.Second);
	for {
		select {
		case <-dm.timeClose:
			{
				return;
			}
		case <-tick.C:
			{
				fmt.Println(time.Now().Format("2006-01-02 15:04:05"));
				//判斷當前下標,如果等於3599則重置為0,否則加1
				if dm.curIndex == 3599 {
					dm.curIndex = 0;
				} else {
					dm.curIndex++;
				}
			}
		}
	}
}

//新增任務
func (dm *DelayMessage) AddTask(t time.Time, key string, exec TaskFunc, params []interface{}) error {
	if dm.startTime.After(t) {
		return errors.New("時間錯誤");
	}
	//當前時間與指定時間相差秒數
	subSecond := t.Unix() - dm.startTime.Unix();
	//計算迴圈次數
	cycleNum := int(subSecond / 3600);
	//計算任務所在的slots的下標
	ix := subSecond % 3600;
	//把任務加入tasks中
	tasks := dm.slots[ix];
	if _, ok := tasks[key]; ok {
		return errors.New("該slots中已存在key為" + key + "的任務");
	}
	tasks[key] = &Task{
		cycleNum: cycleNum,
		exec:     exec,
		params:   params,
	};
	return nil;
}

func main() {
	//建立延遲訊息
	dm := NewDelayMessage();
	//新增任務
	dm.AddTask(time.Now().Add(time.Second*10), "test1", func(args ...interface{}) {
		fmt.Println(args...);
	}, []interface{}{1, 2, 3});
	dm.AddTask(time.Now().Add(time.Second*10), "test2", func(args ...interface{}) {
		fmt.Println(args...);
	}, []interface{}{4, 5, 6});
	dm.AddTask(time.Now().Add(time.Second*20), "test3", func(args ...interface{}) {
		fmt.Println(args...);
	}, []interface{}{"hello", "world", "test"});
	dm.AddTask(time.Now().Add(time.Second*30), "test4", func(args ...interface{}) {
		sum := 0;
		for arg := range args {
			sum += arg;
		}
		fmt.Println("sum : ", sum);
	}, []interface{}{1, 2, 3});

	//40秒後關閉
	time.AfterFunc(time.Second*40, func() {
		dm.Close();
	});
	dm.Start();
}

相關推薦

golang 實現延遲訊息原理方法

package main; import ( "time" "errors" "fmt" ) //延遲訊息 type DelayMessage struct { //當前下標 curIndex int; //環形槽 slots [3600]map[string]

手機定位軟體實現號碼定位找人的原理方法

隨著智慧手機的普及,越來越多的人想要定位別人的或者是好友的手機位置,那麼手機定位精確找人到底靠不靠譜呢?今天就為大家講解下手機定位軟體實現號碼定位的原理和方法。手機號碼定位,還有個學名,也就是基站定位,相信大家並不陌生,它依託於三大運營商的資料庫,以附近三個基站訊號塔為定位點

例項解釋瀑布流圖的實現原理方法

今天博主上網搜了一下關於瀑布流圖的文章,發現實現瀑布流圖的方法大概有“通過JS排版”與“通過後臺排版”兩種。博主認為“通過JS排版”是一種更好的方法,而且網上也是普遍這麼認為的。所以博主先簡單介紹一下“通過後臺排版”的原理,然後在詳細說說“通過JS排版”的原理以及實現過程。

淺談如何通過自媒體渠道實現賺錢的途徑方法?

自媒體 賺錢 思考 眾所周知,隨著互聯網時代的不斷發展,越來越多的網民已經意識到通過網絡能賺到錢。不過在網絡上能賺錢的項目不計其數,包括現在比較火的自媒體,那麽我們怎麽去分辨一個項目的靠譜性呢?我們需要考慮的幾個問題:1. 項目是否需要投資;2. 項目是否有風險;3. 項目的長久性;4. 項目的回

rabbitmq實現延遲訊息(附原始碼)

rabbitmq實現延遲訊息的方案 1. 使用延時佇列 單機不考慮拓展的情況下,可以使用java.util.concurrent包的DelayQueue, 但插入的物件需實現Delayed介面,並實現其getDelay方法。 優點:針對任意訊息佇列均可使用 缺

golang實現簡易的分散式系統方法

本文介紹了golang實現簡易的分散式系統方法,分享給大家,具體如下: 功能 能夠傳送/接收請求和響應 能夠連線到叢集 如果無法連線到群集(如果它是第一個節點),則可以作為主節點啟動節點 每個節點有唯一的標識 能夠在節點之間交換json資料包 接受命令列引數中的所有資訊(將來在我們系

點陣字模生成原理方法

點陣字模生成原理與方法 字模生成原理 本設計中因為使用漢字的點陣顯示,需要提取漢字字模,因此我們首先來了解漢字點陣字模的提取方法。 漢字的點陣字模是從點陣字型檔檔案中提取出來的。例如常用的16×16點陣HZK16檔案,12×12點陣HZK12檔案等等,這些檔案包括了GB

Web GIS原理方法

 開學第三週,正是進入上課狀態,今天一整天的滿課,極度的睏倦,顯然還在適應著上課,本以為一上午的課會小憩一會,但是因為老師的講授,竟然一刻也沒有走神,感覺老師的講課方式很棒,似乎是又給我們打開了一扇窗,特此記錄。 WebGIS顯然是當今GIS發展的一大主要趨勢,WebGIS

瞭解基於視覺的缺陷檢測的原理方法

一、KNN分類器 1.1.1最近鄰演算法      定義:計算未知樣本與所有訓練樣本的距離,並以最近鄰者的類別作為決策未知樣本類別的唯一依據。      缺陷:對噪聲資料過於敏感。      措施:將被決策樣本週邊的多個最近樣本計算在內,擴大參與決策的樣本量,以避免個別資料直接決定決策結果。 1.1.2K-最

Android實現延遲的幾種方法小結

本文例項總結了Android實現延遲的幾種方法。分享給大家供大家參考,具體如下: 一、通過Thread new Thread(){ public void run(){ sleep(***); } }.start(); 通過ProgressDialog的使用來

YAML的Java實現——JYAML基本原理示例(1)匯出資料為YAML格式檔案

1. Overview JYAML是YAML的Java實現,YAML的全稱是YAML Ain't Markup Language,是否定遞迴定義,和LINUX的Linux Is Not UniX是一個意思。其結構之簡單,常常成為匯出或匯入配置檔案、資料結構等應用場景的常用A

YAML的Java實現——JYAML基本原理示例(3)YAML對檔案流的處理

請您先閱讀: 1. FileOutputStream 以流的方式,將資料寫入到YAML檔案中。 /* Output data structure into a YAML file as a

YAML的Java實現——JYAML基本原理示例(2)匯入YAML格式檔案

1. 定義好的YAML檔案testYaml.yaml --- &0 !com.sinosuperman.yaml.Person age: 24 children: &2 !com

百度雲滿速下載原理方法

前言 今天給大家介紹一款好用的開源工具proxyee-down,之前已經測試了好多天了,挺強大,可以滿速下載百度雲裡的檔案,而且不用輸入賬號,因此不存在盜號的可能性。 github地址: 百度雲下載地址: 百度大檔案破解 1.限速與封號 使用過百度雲的朋友肯定知道,百度雲客戶端限速太厲害,我用的翼訊速度

MQ實現延遲訊息”功能

轉載文章:轉自個人微信公眾號[架構師之路];作者:[沈劍] 一、緣起 很多時候,業務有“在一段時間之後,完成一個工作任務”的需求。 例如:滴滴打車訂單完成後,如果使用者一直不評價,48小時後會將自動評價為5星。 一般來說怎麼實現這類“48小時後自動評價為5星

kafka實現訊息丟失精確一次語義(exactly once)處理

在很多的流處理框架的介紹中,都會說kafka是一個可靠的資料來源,並且推薦使用Kafka當作資料來源來進行使用。這是因為與其他訊息引擎系統相比,kafka提供了可靠的資料儲存及備份機制。並且通過消費者位移這一概念,可以讓消費者在因某些原因宕機而重啟後,可以輕易得回到宕機前的位置。 但其實kafka的可靠性也

golang實現常用集合原理介紹

golang本身對常用集合的封裝還是比較少的,主要有陣列(切片)、雙向連結串列、堆等。在工作中可能用到其他常用的集合,於是我自己對常用的集合進行了封裝,並對原理做了簡單介紹,程式碼庫地址:https://github.com/chentaihan/container,程式碼都是經過測試的,歡迎下載使用,反饋

分頁技術原理實現之分頁的意義及方法(一)

轉載自https://www.jb51.net/article/86326.htm。 什麼是分頁技術  分頁,是一種將所有資料分段展示給使用者的技術.使用者每次看到的不是全部資料,而是其中的一部分,如果在其中沒有找到自習自己想要的內容,使用者可以通過制定頁碼或是翻頁的方式轉換可見內容,

機器學習方法(四):決策樹Decision Tree原理實現技巧

歡迎轉載,轉載請註明:本文出自Bin的專欄blog.csdn.net/xbinworld。 技術交流QQ群:433250724,歡迎對演算法、技術、應用感興趣的同學加入。 前面三篇寫了線性迴歸,lasso,和LARS的一些內容,這篇寫一下決策樹這個經典的分

《機器學習實戰》AdaBoost方法的演算法原理程式實現

一、引言提升(boosting)方法是一種常用的統計學習方法,應用廣泛且有效,在分類問題中,它通過改變訓練樣本的權重,學習多個分類器,並將這些分類器進行線性組合,提高分類的效能。對於分類問題,給定一個訓練樣本集,比較粗糙的分類規則(弱分類器),要比精確分類規則(強分類器)容易