作者归档:F.Y

tengine安装ngx_devel_kit和echo模块

git clone https://github.com/agentzh/echo-nginx-module.git
git clone https://github.com/simpl/ngx_devel_kit.git
./configure --prefix=/usr/local/tengine --add-module=/root/ngx_devel_kit --with-http_lua_module --add-module=/root/echo-nginx-module

ndk 需要静态编译,不能动态加载,意思即是重新编译tengine ,参考

http://www.coctec.com/docs/service/show-post-11191.html

golang mssqlserver复制记录总数对比工具

使用mssqlserver复制备份,某天突然发现复制显示一切正常,但是记录数又不一样,明显是停止了,虽然还没有搞懂怎么回事,所以想了这样一个工具来检查复制。程序用go写的,顺便练习一下golang 代码。

package main

import (
	"fmt"
	"log"
	//	"os"
	//	"strings"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mssql"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
	"github.com/lxn/win"
)

var (
	err         error
	sqliteDB    *gorm.DB
	mssqlDB_src *gorm.DB
	mssqlDB_dsc *gorm.DB
	tvChan      chan TbRow
)

type DsnEnrty struct {
	Id   uint   `gorm:"primary_key"`
	Name string `gorm:"size:64"`
	Src  string `gorm:"size:512"`
	Dest string `gorm:"size:512"`
}
type MyMainWindow struct {
	*walk.MainWindow
	model        *EnvModel
	lb           *walk.ListBox
	te           *walk.TextEdit
	addButton    *walk.Action
	deleteButton *walk.Action
	Name_edit    *walk.LineEdit
	Src_edit     *walk.LineEdit
	Dest_edit    *walk.LineEdit
	Tv           *walk.TableView
	ModelTV      *TvModel
}

type EnvModel struct {
	walk.ListModelBase
	items []DsnEnrty
}

func NewEnvModel() *EnvModel {
	//env := os.Environ()
	//var ListDsn []DsnEnrty
	//ListDsn, err = sqliteDB.Model(&DsnEnrty{}).Find(&ListDsn)

	m := &EnvModel{items: make([]DsnEnrty, 100)}

	sqliteDB.Find(&m.items)
	return m
}

func (m *EnvModel) ItemCount() int {
	return len(m.items)
}

func (m *EnvModel) Value(index int) interface{} {
	return m.items[index].Name
}

type TbRow struct {
	Index   string
	Tname   string
	SrcNum  int
	DestNum int
	Result  string
}

type TvModel struct {
	walk.TableModelBase
	items []TbRow
}

func NewTvModel() *TvModel {
	//m := new(TvModel)
	//m.items = make([]TbRow, 100)
	m := &TvModel{items: []TbRow{}}
	//m.ResetRows()
	return m
}
func (m *TvModel) ResetRows() {
	//m.items = make([]TbRow, 1)
	item := TbRow{}

	item.Tname = "fy"
	item.SrcNum = 100
	item.DestNum = 200
	m.items = append(m.items, item)
	//m.items[0] = item
	m.PublishRowsReset()
}
func (m *TvModel) RowCount() int {
	return len(m.items)
}
func (m *TvModel) Value(row, col int) interface{} {
	item := m.items[row]

	switch col {
	case 0:
		return item.Index
	case 1:
		return item.Tname

	case 2:
		return item.SrcNum

	case 3:
		return item.DestNum

	case 4:
		return item.Result
	}

	panic("unexpected col")
}

func (mw *MyMainWindow) lb_CurrentIndexChanged() {
	idx := mw.lb.CurrentIndex()
	if idx < 0 || idx > len(mw.model.items) {
		return
	}
	dsn := mw.model.items[idx]
	mw.Name_edit.SetText(dsn.Name)
	mw.Src_edit.SetText(dsn.Src)
	mw.Dest_edit.SetText(dsn.Dest)
}

func (mw *MyMainWindow) lb_ItemActivated() {
	value := mw.model.items[mw.lb.CurrentIndex()].Dest

	walk.MsgBox(mw, "Value", value, walk.MsgBoxIconInformation)
}
func (mw *MyMainWindow) tv_showtableview() {
	for {
		select {
		case row := <-tvChan:
			//fmt.Printf("%#v\n", row)
			mw.ModelTV.items = append(mw.ModelTV.items, row)
			mw.ModelTV.PublishRowsReset()
		}
	}
}

type tablelist struct {
	Name string
}

func (mw *MyMainWindow) run_get_sql_tables_info() {
	go mw.get_sql_tables_info()
}
func (mw *MyMainWindow) get_sql_tables_info() {

	idx := mw.lb.CurrentIndex()
	if idx < 0 {
		walk.MsgBox(mw, "出错了", "请选择左边条目再操作", walk.MsgBoxIconError)
		return
	}
	conninfo := mw.model.items[idx]
	mssqlDB_src, err = gorm.Open("mssql", conninfo.Src)
	_, err = get_mssql_version(mssqlDB_src)
	if err != nil {
		walk.MsgBox(mw, "连接源服务器出错", err.Error(), walk.MsgBoxIconError)
		return
	}
	mssqlDB_dsc, err := gorm.Open("mssql", conninfo.Dest)
	_, err = get_mssql_version(mssqlDB_src)
	if err != nil {
		walk.MsgBox(mw, "连接源服务器出错", err.Error(), walk.MsgBoxIconError)
		return
	}
	rows, err := mssqlDB_src.Raw("SELECT Name FROM SysObjects Where XType='U' ORDER BY Name").Rows()
	defer rows.Close()

	//var tmp string
	//var tblist []string
	//var tab_items []TbRow
	for rows.Next() {
		var tmp string
		rows.Scan(&tmp)

		tb := TbRow{}
		tb.Index = conninfo.Name
		tb.Tname = tmp
		mssqlDB_src.Table(tmp).Count(&tb.SrcNum)
		mssqlDB_dsc.Table(tmp).Count(&tb.DestNum)
		//tab_items = append(tab_items, tb)
		if tb.SrcNum == tb.DestNum {
			tb.Result = "-"
		} else {
			tb.Result = "X"
		}
		tvChan <- tb
	}
	defer mssqlDB_src.Close()
	defer mssqlDB_dsc.Close()
}
func get_mssql_version(db *gorm.DB) (versions string, err error) {
	sqlRow := db.Raw("select @@VERSION").Row()

	err = sqlRow.Scan(&versions)
	if err != nil {
		return "", err
	}
	return versions, nil
}

func main() {

	sqliteDB, err = gorm.Open("sqlite3", "./sqlserver_sync_checker.db")
	if err != nil {
		log.Fatal("sqlite3 open error:", err)
	}
	if !sqliteDB.HasTable(&DsnEnrty{}) {
		sqliteDB.AutoMigrate(&DsnEnrty{})
	}

	mw := &MyMainWindow{model: NewEnvModel(), ModelTV: NewTvModel()}
	tvChan = make(chan TbRow, 10)
	go mw.tv_showtableview()

	if _, err := (MainWindow{
		AssignTo: &mw.MainWindow,
		Title:    "mssql server 表记录总数对比",
		MinSize:  Size{600, 520},
		Size:     Size{600, 600},
		Layout:   VBox{MarginsZero: true},
		//ToolBar:  mw.newToolBar(),
		Children: []Widget{
			HSplitter{
				Children: []Widget{
					Composite{
						Layout: Grid{Columns: 2},
						Children: []Widget{
							ListBox{
								AssignTo: &mw.lb,
								Model:    mw.model,
								OnCurrentIndexChanged: mw.lb_CurrentIndexChanged,
								OnItemActivated:       mw.lb_ItemActivated,
							},
							Label{
								ColumnSpan: 2,
								Text:       "名称:",
							},
							LineEdit{
								AssignTo:   &mw.Name_edit,
								ColumnSpan: 2,
								Text:       "新名字",
							},
							Label{
								ColumnSpan: 2,
								Text:       "源DSN:",
							},
							LineEdit{
								AssignTo:   &mw.Src_edit,
								ColumnSpan: 2,
								Text:       "sqlserver://username:password@localhost:1433?database=dbname;encrypt=disable",
							},
							Label{
								ColumnSpan: 2,
								Text:       "目标DSN:",
							},
							LineEdit{
								AssignTo:   &mw.Dest_edit,
								ColumnSpan: 2,
								Text:       "sqlserver://username:password@localhost:1433?database=dbname;encrypt=disable",
							},
							PushButton{
								// AssignTo: &acceptPB,
								Text:       "更新",
								ColumnSpan: 2,
								OnClicked: func() {
									idx := mw.lb.CurrentIndex()
									if idx < 0 {
										walk.MsgBox(mw, "出错了", "请选择数据再操作", walk.MsgBoxIconError)
										return
									}

									dsn := mw.model.items[idx]
									dsn.Name = mw.Name_edit.Text()
									dsn.Src = mw.Src_edit.Text()
									dsn.Dest = mw.Dest_edit.Text()
									sqliteDB.Model(&DsnEnrty{}).Where("id=?", dsn.Id).Update(&dsn)
									//mw.lb.SetModel(NewEnvModel())
									//mw.model = NewEnvModel()
									mw.model = NewEnvModel()
									mw.lb.SetModel(mw.model)
									walk.MsgBox(mw, "提示", "保存成功", walk.MsgBoxIconInformation)
								},
							},
							PushButton{
								// AssignTo:  &cancelPB,
								Text:       "新建",
								ColumnSpan: 2,
								OnClicked: func() {
									dsn := DsnEnrty{}
									dsn.Name = mw.Name_edit.Text()
									dsn.Src = mw.Src_edit.Text()
									dsn.Dest = mw.Dest_edit.Text()
									sqliteDB.Model(&DsnEnrty{}).Create(&dsn)
									mw.model = NewEnvModel()
									mw.lb.SetModel(mw.model)
									walk.MsgBox(mw, "提示", "保存成功", walk.MsgBoxIconInformation)
								},
							},
							PushButton{
								// AssignTo:  &cancelPB,
								Text:       "删除",
								ColumnSpan: 2,
								OnClicked: func() {
									idx := mw.lb.CurrentIndex()
									if idx < 0 {
										walk.MsgBox(mw, "出错了", "请选择数据再操作", walk.MsgBoxIconError)
										return
									}
									dsn := mw.model.items[idx]
									message := fmt.Sprintf("确定要删除记录 '%s'?", dsn.Name)
									ret := walk.MsgBox(mw, "删除记录", message, walk.MsgBoxYesNo)
									if ret == win.IDYES {

										sqliteDB.Where("id=?", dsn.Id).Delete(DsnEnrty{})
										mw.model = NewEnvModel()
										mw.lb.SetModel(mw.model)
										walk.MsgBox(mw, "提示", "删除成功", walk.MsgBoxIconInformation)
									}

								},
							},
							PushButton{
								// AssignTo:  &cancelPB,
								Text:       "源-测试连接",
								ColumnSpan: 2,
								OnClicked: func() {
									dsn := mw.Src_edit.Text()
									if len(dsn) == 0 {
										walk.MsgBox(mw, "出错了", "DSN不能为空", walk.MsgBoxIconError)
										return
									}
									db, err := gorm.Open("mssql", dsn)
									defer db.Close()
									sqlver, err := get_mssql_version(db)
									if err != nil {
										walk.MsgBox(mw, "出错了", err.Error(), walk.MsgBoxIconError)
									} else {
										walk.MsgBox(mw, "提示", sqlver, walk.MsgBoxIconInformation)
									}
								},
							},
							PushButton{
								// AssignTo:  &cancelPB,
								Text:       "目标-测试连接",
								ColumnSpan: 2,
								OnClicked: func() {
									dsn := mw.Src_edit.Text()
									if len(dsn) == 0 {
										walk.MsgBox(mw, "出错了", "DSN不能为空", walk.MsgBoxIconError)
										return
									}
									dbdest, err := gorm.Open("mssql", dsn)
									defer dbdest.Close()
									sqlver, err := get_mssql_version(dbdest)
									if err != nil {
										walk.MsgBox(mw, "出错了", err.Error(), walk.MsgBoxIconError)
									} else {
										walk.MsgBox(mw, "提示", sqlver, walk.MsgBoxIconInformation)
									}
								},
							},
						},
					},

					Composite{
						Layout: Grid{Columns: 2},
						Children: []Widget{
							PushButton{
								// AssignTo:  &cancelPB,
								Text:       "获取对比信息",
								ColumnSpan: 1,
								OnClicked:  mw.run_get_sql_tables_info,
							},
							PushButton{
								// AssignTo:  &cancelPB,
								Text:       "清空结果",
								ColumnSpan: 1,
								OnClicked: func() {
									mw.ModelTV.items = []TbRow{}
									mw.ModelTV.PublishRowsReset()
								},
							},

							TableView{
								ColumnSpan:            2,
								AssignTo:              &mw.Tv,
								AlternatingRowBGColor: walk.RGB(239, 239, 239),
								CheckBoxes:            false,
								ColumnsOrderable:      false,
								MultiSelection:        true,
								Columns: []TableViewColumn{
									{Title: "配置", Width: 150},
									{Title: "表", Width: 250},
									{Title: "源记录数", Width: 100},
									{Title: "目标记录数", Width: 100},
									{Title: "结果", Width: 50},
								},
								StyleCell: func(style *walk.CellStyle) {

								},
								Model: mw.ModelTV,
								OnSelectedIndexesChanged: func() {
									//fmt.Printf("SelectedIndexes: %v\n", tv.SelectedIndexes())
								},
							},
						},
					},
				},
			},
		},
	}.Run()); err != nil {
		log.Fatal(err)
	}
}

 

golang并发控制

在多线程编程中,我经常会用到2个方面的线程控制,一是启停线程,二是控制线程数量,在golang中,启动的是协程,一个比线程更好的东西。为了实现这两个功能,在github  fork  grtm 并进行了功能增强

更多例子请看 github.com/fy138/grtm

一、启停线程

package main

import (
	"fmt"
	//	"runtime"
	"time"

	"github.com/fy138/grtm"
)

func myfunc(me interface{}) {
	fmt.Println("hello+" + me.(string))
	time.Sleep(time.Second * 2)
}
func main() {
	gm := grtm.NewGrManager()
	//在创建gm后新建一个进程接收出错信息
	go func(gm *grtm.GrManager) {
		for {
			select {
			case err := <-gm.ErrChan:
				fmt.Println("Received error:", err.Error())
			case notify := <-gm.NotiChan:
				fmt.Println("Received Notify:", notify)
			}
		}
	}(gm)

	gm.NewLoopGoroutine("myfunc", myfunc, "1")
	gm.NewLoopGoroutine("myfunc2", myfunc, "2")
	time.Sleep(time.Second * 3)

	gm.StopLoopGoroutine("aaaaaa")
	time.Sleep(time.Second * 3)

	gm.StopLoopGoroutine("myfunc2")
	time.Sleep(time.Second * 3)

	gm.NewLoopGoroutine("myfunc", myfunc, "1")
	time.Sleep(time.Second * 3)

	for {
		for k, v := range gm.GetAllTask() {
			fmt.Printf("task name:%s,task id:%d,task name2:%s\n", k, v.Gid, v.Name)
		}
		fmt.Printf("NumTask:%d\n", gm.GetTaskTotal())
		time.Sleep(time.Second * 1)
	}
}

输出是这样的

hello+1
hello+2
hello+1
hello+2
Received error: not found goroutine name :aaaaaa
hello+1
hello+2
hello+1
Received Notify: gid[1597969999]quit
hello+1
Received error: goroutine channel already defined: "myfunc"
hello+1
hello+1
task name:myfunc,task id:5577006791947779410,task name2:myfunc
NumTask:1
task name:myfunc,task id:5577006791947779410,task name2:myfunc
NumTask:1
hello+1
task name:myfunc,task id:5577006791947779410,task name2:myfunc
NumTask:1

二、限制线程数量

package main

import (
	"fmt"
	"runtime"
	"time"

	"github.com/fy138/grtm"
)

func main() {
	go func() {
		for {
			//get  goroutine total
			fmt.Println("go goroutines:", runtime.NumGoroutine())
			time.Sleep(time.Second * 1)
		}

	}()
	//建立线程池
	pool_1 := grtm.NewPool(3)
	pool_2 := grtm.NewPool(2)
	for i := 100; i >= 1; i-- {
		fmt.Println("I=", i)
		//通过通道来限制goroutine 数量
		/* 下面是第一种调用方法 */
		pool_1.LimitChan <- true //importan
		pool_1.AddTask(Download, i, "Download_1")

		/* 下面是第二种调用方法 */
		pool_2.LimitChan <- true //importan
		go func(i int, str string) {
			Download2(i, str)
			//函数执行完释放通道
			defer func() {
				<-pool_2.LimitChan
			}()
		}(i, "Download_2")

	}
	time.Sleep(time.Second * 20) //防止主线程提前退出
}

func Download(args ...interface{}) {
	time.Sleep(2 * time.Second)
	fmt.Printf("%s => %d \n", args[0].([]interface{})[1].(string), args[0].([]interface{})[0].(int))
}
func Download2(i int, str string) {
	time.Sleep(2 * time.Second)
	fmt.Printf("%s => %d \n", str, i)
}

输出结果

I= 100
go goroutines: 4
I= 99
I= 98
go goroutines: 9
Download_2 => 100
I= 97
Download_1 => 100
go goroutines: 9
Download_2 => 99
I= 96
Download_1 => 99
Download_1 => 98
go goroutines: 8
Download_2 => 98
I= 95
Download_1 => 97
go goroutines: 8
Download_2 => 97
I= 94
Download_1 => 96
go goroutines: 8
Download_2 => 96
I= 93
Download_1 => 95
go goroutines: 8
Download_2 => 95
I= 92
Download_1 => 94
go goroutines: 8
Download_2 => 94
I= 91

 

golang 小文件写入测试程序

最近总是怀疑磁盘有问题,所以写了一个小程序,测试磁盘写入程序

package main

import (
	"fmt"
	"io/ioutil"
	//	"log"
	"os"
	"runtime"
	"strconv"
	"time"

	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
)

var (
	limitChan chan bool
	t         = time.Tick(time.Second)
	org_path  string
)

type MyMainWindow struct {
	*walk.MainWindow
	edit           *walk.TextEdit
	bnt_selectFile *walk.PushButton
	bnt_start      *walk.PushButton
	path           string
	sbi_gonum      *walk.StatusBarItem
	sbi_status     *walk.StatusBarItem
	file_number    *walk.LineEdit
	go_number      *walk.LineEdit
}

func (mw *MyMainWindow) bnt_selectFile_action() {

	dlg := new(walk.FileDialog)
	dlg.FilePath = mw.path
	dlg.Title = "请选择配置目录..."
	//dlg.Filter = "配置文件 (*.ini)|*.ini|所有文件 (*.*)|*.*"

	if ok, err := dlg.ShowBrowseFolder(mw); err != nil {
		//mw.edit.AppendText("Error : File Open\r\n")
		walk.MsgBox(mw, "出错了", "请选择配置目录", walk.MsgBoxIconError)
		return
	} else if !ok {
		//mw.edit.AppendText("Cancel\r\n")
		return
	}
	//mw.edit.SetText("")
	mw.path = dlg.FilePath
	org_path = mw.path //防止目录不断重复加深
	mw.sbi_status.SetText("写入目录:" + mw.path)
}
func (mw *MyMainWindow) bnt_start_action() {

	if len(mw.path) == 0 {
		//walk.MsgBox(mw, "出错了", "请选择目录", walk.MsgBoxIconError)
		mw.path = "./testdir"
		//return
	} else {
		mw.path = mw.path + "/testdir"
	}
	mw.sbi_status.SetText("写入目录:" + mw.path)
	go dotest(mw)

}

func write_file(path string, data []byte) {
	err := ioutil.WriteFile(path, data, os.ModeAppend)
	if err != nil {
		//log.Print("write file error:", err.Error())
	}
	defer func() {
		<-limitChan //释放队列
	}()
}
func show_goroutine(mw *MyMainWindow) {
	go func() {
		for {
			select {
			case <-t:
				//每秒打印一次goroutine数量
				mw.sbi_gonum.SetText(fmt.Sprintf("NumGoroutine: %d", runtime.NumGoroutine()))
			}
		}
	}()
}
func dotest(mw *MyMainWindow) {

	path := mw.path
	number, _ := strconv.Atoi(mw.file_number.Text())
	ChanNum, _ := strconv.Atoi(mw.go_number.Text())

	limitChan = make(chan bool, ChanNum)
	filecount := []byte(mw.edit.Text())
	if len(filecount) == 0 {
		walk.MsgBox(mw, "出错了", "内容不能为空", walk.MsgBoxIconError)
		return
	}

	mw.bnt_selectFile.SetEnabled(false)
	mw.bnt_start.SetEnabled(false)

	file_len := float32(len(filecount))
	util_mb := float32(1024 * 1024)
	//log.Printf("template lengh:%f mb", file_len/util_mb)

	_, err := os.Stat(path)
	if err != nil {
		os.MkdirAll(path, os.ModePerm)
	}

	t1 := time.Now().UnixNano()

	var size float32 = 0.00
	for i := 1; i < number; i++ {
		size += file_len
		//ioutil.WriteFile(, filecount, os.ModeAppend)
		limitChan <- true
		go write_file(fmt.Sprintf("%s/%d.txt", path, i), filecount)
	}
	t2 := time.Now().UnixNano()
	t_size := size / util_mb
	t_ms := (t2 - t1) / 1e6
	t_s := (t2 - t1) / 1e9
	if t_s == 0 {
		t_s = 1
	}

	mw.sbi_status.SetText(fmt.Sprintf("内容:%f kb,共写入:%f mb,花费:%d ms,每秒写入%d个文件", file_len/1024, t_size, t_ms, int64(number)/t_s))
	mw.bnt_selectFile.SetEnabled(true)
	mw.bnt_start.SetEnabled(true)
	mw.path = org_path
}
func main() {
	mw := &MyMainWindow{}

	go show_goroutine(mw)

	MW := MainWindow{
		AssignTo: &mw.MainWindow,
		Title:    "文件写入速度测试 v1.0",
		MinSize:  Size{500, 600},
		Size:     Size{500, 600},

		Layout: VBox{},
		Children: []Widget{
			Composite{
				Layout: Grid{Columns: 2},
				Children: []Widget{
					Label{
						Text: "写入文件数量:",
					},
					LineEdit{
						AssignTo: &mw.file_number,
						Text:     "1000",
					},
					Label{
						Text: "线程数量:",
					},
					LineEdit{
						AssignTo: &mw.go_number,
						Text:     "10",
					},
				},
			},
			Composite{
				Layout: Grid{Columns: 1},
				Children: []Widget{
					PushButton{
						AssignTo:  &mw.bnt_selectFile,
						Text:      "选择测试目录...",
						OnClicked: mw.bnt_selectFile_action,
					},
					PushButton{
						AssignTo:  &mw.bnt_start,
						Text:      "开始",
						OnClicked: mw.bnt_start_action,
					},

					TextEdit{
						AssignTo: &mw.edit,
						ReadOnly: false,
						VScroll:  true,
					},
				},
			},
		},
		StatusBarItems: []StatusBarItem{
			StatusBarItem{
				AssignTo: &mw.sbi_gonum,
				//Text:     "准备中...",
				Width: 120,
			},
			StatusBarItem{
				AssignTo: &mw.sbi_status,
				Text:     "准备中...",
				Width:    600,
			},
		},
	}

	if _, err := MW.Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

}

编译方法请查看
https://github.com/lxn/walk

golang多线程控制,小文件写入测试

最近遇到需要测试共享盘小文件写入的问题,所以自己写了一个程序,测试小文件写入速度,源码如下

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"time"
)

var (
	limitChan   chan bool 
	t         = time.Tick(time.Second)
)

func watching() {
	fmt.Printf("NumGoroutine: %d\n", runtime.NumGoroutine())
}
func write_file(path string, data []byte) {
	err := ioutil.WriteFile(path, data, os.ModeAppend)
	if err != nil {
		log.Print("write file error:", err.Error())
	}
	defer func() {
		<-limitChan //释放队列
	}()
}
func init() {
	go func() {
		for {
			select {
			case <-t:
				watching() //每秒打印一次goroutine数量
			}
		}
	}()
}
func main() {

	path := flag.String("path", "./testdir", "test path")
	template := flag.String("template", "template.txt", "write file template")
	number := flag.Int("num", 1000, "number of files")
	ChanNum := flag.Int("gonum", 10, "number of goroutine")
	flag.Parse()

	limitChan = make(chan bool, *ChanNum) //重新定义

	filecount, err := ioutil.ReadFile(*template)
	if err != nil {
		log.Fatal("read template error:", err)
	}
	file_len := float32(len(filecount))
	util_mb := float32(1024 * 1024)
	log.Printf("template lengh:%f mb", file_len/util_mb)

	_, err = os.Stat(*path)
	if err != nil {
		os.MkdirAll(*path, os.ModePerm)
	}

	t1 := time.Now().UnixNano()
	i := 1
	var size float32 = 0.00
	for {
		size += file_len
		//ioutil.WriteFile(, filecount, os.ModeAppend)
		limitChan <- true
		go write_file(fmt.Sprintf("%s/%d.txt", *path, i), filecount)
		i++
		if i == *number {
			break
		}
	}
	t2 := time.Now().UnixNano()
	t_size := size / util_mb
	t_ms := (t2 - t1) / 1e6
	t_s := (t2 - t1) / 1e9
	if t_s == 0 {
		t_s = 1
	}
	log.Printf("write lengh:%f mb", t_size)
	log.Printf("this time is:%d ms", t_ms)
	log.Printf("write file speed:%d files of 1 second", int64(*number)/t_s)
}

本程序加入了队列控制goroutine的数量,由于对goroutine数量控制不是很好,之前写了一个小程序进行验证

package main

import (
	"fmt"
	"time"
)

var (
	limt chan bool
	t    = time.Tick(time.Second)
)

func main() {
	go func() {
		for {
			select {
			case <-t:

				for i := 1; i <= 5; i++ {
					<-limt
				}
			}
		}
	}()
	limt = make(chan bool, 10)
	i := 1
	for {
		fmt.Println(i)
		limt <- true
		i++
	}
}

参考goroutine控制
http://blog.csdn.net/yxw2014/article/details/20957429
http://blog.csdn.net/miao0916/article/details/55045894

sqlserver收缩数据库日志脚本

因为需要迁移数据库,但是发现日志文件非常大,所以需要收缩数据库后再迁移,但是一个服务器有几个数据库,每个都点一次感觉太累了。在没有sqlserver编程基础的情况下,在百度搜了一下相关资料,写出了这个脚本,用起来感觉还好。所以在这里分享

use master
go 
declare mydbs cursor scroll
for Select Name FROM Master..SysDatabases
open mydbs
Declare @dbname nvarchar(255)
fetch next from mydbs into @dbname

while(@@FETCH_STATUS=0)
begin
	if @dbname!='master' and @dbname !='model' and @dbname!='msdb' and @dbname!='tempdb'
	begin

	declare @sqlquery nvarchar(1024)
		set @sqlquery='USE master
--GO
ALTER DATABASE '+@dbname+' SET RECOVERY SIMPLE WITH NO_WAIT
--GO
ALTER DATABASE '+@dbname+' SET RECOVERY SIMPLE   
--GO
USE '+@dbname+'
--GO
DBCC SHRINKFILE (N'''+@dbname+'_Log'', 100, TRUNCATEONLY)
--GO
USE master
--GO
ALTER DATABASE '+@dbname+' SET RECOVERY FULL WITH no_wait
--GO
ALTER DATABASE '+@dbname+' SET RECOVERY FULL   
--GO'
		EXEC SP_EXECUTESQL @sqlquery
		--print @sqlquery

	end
	fetch next from mydbs into @dbname
end
close mydbs
deallocate mydbs
go

 

Golang控制goroutine的启动与关闭

在用walk写一个窗口程序,当需要执行其它任务的时候,你要用一个新的线程去做,所以想到任务的停止和启动。在go中,很容易可以做到这些,因为go是通过管道通迅的。

package main

import (
	"fmt"
	"time"
)

func p() {
	fmt.Println("test")
	time.Sleep(time.Second * 3)

}
func worker(ch chan int) {
	for {
		select {
		case <-ch:
			return //收到信号就退出线程
		default:
			p()
		}
	}
}
func main() {
	ch := make(chan int)

	go worker(ch)

	time.Sleep(time.Second * 10)
	ch <- 1  //发送退出线程的命令
	fmt.Println("finish.")
	for {
	}

}

 

golang int转[]byte

今天遇到int 转[]byte的问题,在百度搜了很多结果,发现很复杂,突然想到string转[]byte非常方便,那么int转string也很方便,下面是获取程序pid并写入pid文件的代码,非常容易,os.Getpid()反回int类型,strconv.Itoa 将int转string,
[]byte将string转byte

err = ioutil.WriteFile(PidFile, []byte(strconv.Itoa(os.Getpid())), 0644)

 

golang模拟点击浏览器

发现一个很好玩的浏览器模拟操作包,下面演示一下,打开网站,点击某个链接

package main

import (
	"fmt"
	"time"

	"github.com/go-vgo/robotgo"
	"sourcegraph.com/sourcegraph/go-selenium"
)

func main() {
	var webDriver selenium.WebDriver
	var err error
	caps := selenium.Capabilities(map[string]interface{}{"browserName": "firefox"})
	if webDriver, err = selenium.NewRemote(caps, "http://localhost:9515"); err != nil {
		fmt.Printf("Failed to open session: %s\n", err)
		return
	}
	defer webDriver.Quit()

	err = webDriver.Get("http://www.yiyou.org")
	if err != nil {
		fmt.Printf("Failed to load page: %s\n", err)
		return
	}

	robotgo.MoveMouseSmooth(323, 186) //移动鼠标
	robotgo.MouseClick("left", true) //单击
	time.Sleep(time.Second * 5)
	robotgo.MoveMouseSmooth(422, 412)
	robotgo.MouseClick("left", true)
	time.Sleep(time.Second * 5)

	cookies, err := webDriver.GetCookies() //获取cookie
	if err != nil {
		fmt.Println(err)
	}
	time.Sleep(time.Second * 5)
	fmt.Print("Cookie:", cookies)
	fmt.Print(robotgo.GetMousePos())
	for {
	}
}

需要先运行chromedriver,下载地址:
https://chromedriver.storage.proxy.ustclug.org/index.html