顯示文章

這裡允許您檢視這個會員的所有文章。請注意, 您只能看見您有權限閱讀的文章。


文章 - Yamaka

頁: 1 [2] 3 4 ... 164
31
雜七雜八 / Re: 大家新年快樂!
« 於: 2016-02-09 19:22 »
‧★,:*:‧\( ̄▽ ̄)/‧:*‧°★*

32
雜七雜八 / 今天真的冷啊!!
« 於: 2016-01-23 11:09 »
今天真的有夠冷
桌機CPU風扇一直在0RPM
害我一直以為是不是風扇掛了  :D

大家要包暖一點喔!^___^

33
有時候新安裝的 ubuntu 會有一種情況
開機時會卡在網路卡,螢幕顯示要等60秒
之前也一直找不到解法,後來我用那串提示字串
直接在系統裡搜尋,結果就找到某個程式碼(.py)裡
有這個字串,於是就直接去修改這個程式碼
將60秒改成2秒,開機進入桌面後網路卡也有正常啟動.....

雖然是不同的環境與問題,參考看看嘍! ^___^

34
fdisk -l 其實不是消失
而是代號會變 , 幾小時之後又變回來

不過小弟找到備份方法了
就是備份在同學那 ...
只是 .. 布袋戲部分 , 她看過就刪除
... 畢竟時在容量太大了

剛剛也碰到這種情況了
本來是 sda, 莫名奇妙就變成 sdb
之前好像也有過1,2次吧
不過這棵是用在 zfs raid10
開機中資料還可以正常存取
重開機後 zfs 會自動修正資料

35
鞗改了一下,我把那一大串指令改寫成 .sh 檔放在 /usr/local/bin

代碼: [選擇]
$ cat /usr/local/bin/cce.sh
#!/bin/bash
CCE=$1
CCE="${CCE##*/}"
CCE="/tmp/cc/${CCE%%.*}"
[ ! -d "/tmp/cc" ] && mkdir /tmp/cc/
if [ ! -f ${CCE} ] || [ `date -r $1 +%s` -gt `date -r ${CCE} +%s` ]; then
  /usr/bin/env clang++ -O3 -std=c++14 -o ${CCE} $1
fi
shift
#echo ${CCE}
${CCE} $@

$ sudo chmod +x /usr/local/bin/cce.sh

c++ 第一行就可以簡潔一點

代碼: [選擇]
$ cat ex045.cc
//usr/local/bin/cce.sh $0 $@;exit
#include <iostream>
 
int main(int argc, char **argv) {
  std::cout << "Hello, World!!\n"
            << argc << "\n" << argv[1] << " " << argv[2]
            << std::endl;
  return 0;
}

執行效果一樣 ^^

$ time ./ex045.cc 123 abc
Hello, World!!
3
123 abc

real   0m0.026s
user   0m0.008s
sys   0m0.012s



36
好久以前試過一次,不過沒試出來,今天再拿出來玩,終於弄出來了XD

目標是這樣:編寫好 c/c++ 程式碼之後,不手動跑 make 或是 gcc/g++ 編譯,
而是直接改原始碼的權限為可執行,然後就.....直接執行這個檔,例如:

代碼: [選擇]
$ cat ex045.cc

#include <iostream>
 
int main(int argc, char **argv) {
  std::cout << "Hello, World!!\n"
            << argc << "\n" << argv[1] << " " << argv[2]
            << std::endl;
  return 0;
}

引用
$ chmod +x ex045.cc
$ time ./ex045.cc 123 abc
Hello, World!!
3
123 abc

real   0m0.365s
user   0m0.304s
sys   0m0.048s


沒錯,就是要能夠直接跑 ./ex045.cc,不是編譯後的 ./ex045
中間測試過程就略過不提了,直接貼結果出來

代碼: [選擇]
$ cat ex045.cc

//bin/true;CCE=$0;CCE="${CCE##*/}";CCE="/tmp/cc/${CCE%%.*}";[ ! -d "/tmp/cc" ]&&mkdir /tmp/cc/;if [ ! -f ${CCE} ] || [ `date -r $0 +%s` -gt `date -r ${CCE} +%s` ]; then /usr/bin/env clang++ -O3 -std=c++14 -o ${CCE} $0;fi; ${CCE} $@;exit
#include <iostream>
 
int main(int argc, char **argv) {
  std::cout << "Hello, World!!\n"
            << argc << "\n" << argv[1] << " " << argv[2]
            << std::endl;
  return 0;
}

跟其他 shell script 一樣,第一行對 c++ 來說是是註解
但卻是一串 bash 指令,這些指令會判斷原始碼與執行檔的檔案時間
必要的話就啟動編譯器編譯進行編譯,執行檔則丟到 /tmp/cc
最後再執行 /tmp/cc 資料夾裡的執行檔
這行最後面的『 exit 』指令是必要的
少了這行,bash 會一直往下讀取指令並執行...

第一次執行會先進行編譯,如果程式碼未修改過
之後再執行就不會編譯(直到 reboot)

引用
$ time ./ex045.cc 123 abc
Hello, World!!
3
123 abc

real   0m0.365s
user   0m0.304s
sys   0m0.048s
$ time ./ex045.cc 123 abc
Hello, World!!
3
123 abc

real   0m0.022s
user   0m0.008s
sys   0m0.008s



37
程式討論版 / [Golang] select-case
« 於: 2015-09-06 15:41 »
select case 每次都會隨機選擇一個已進入『備妥』狀態的 case 來執行
而且每一輪進入 select 時,每一個 case 被選中的機率都一樣
不會輪流選擇,完全是隨機。

下面範例是網路上抓來修改的
每個 case 增加一個計數器
最後將進入每個 case 的次數印出

從執行結果可以看到,每次進入 select
每一個 case 後的函數都會被呼叫一次
但是最後只會隨機選擇一個 case 進入

Code:
代碼: [選擇]
package main

import (
  "fmt"
)

func main() {
  ch1 := make(chan bool, 1)
  c1, c2, c3, c4, c5 := 0, 0, 0, 0, 0

  func() {
    defer func() {
      fmt.Println(c1, c2, c3, c4, c5)
    }()

    for {
      fmt.Println("start")
      select {
      case ch1 <- callMe("c1"):
        c1++
        fmt.Println("in case1")
      case ch1 <- callMe("c2"):
        c2++
        fmt.Println("in case2")
      case ch1 <- callMe("c3"):
        c3++
        fmt.Println("in case3")
      case ch1 <- callMe("c4"):
        c4++
        fmt.Println("in case4")
      case ch1 <- callMe("c5"):
        c5++
        fmt.Println("in case5")
      }
      fmt.Println("end")
      <-ch1
      if c1+c2+c3+c4+c5 >= 100 {
        return
      }
    }
  }()
}

func callMe(s string) bool {
  fmt.Println("in", s)
  return true
}

每次跑完的結果都會不同,下面列出跑3次的結果

Result:
引用
23 18 17 30 12
21 18 18 24 19
26 11 20 25 18

http://play.golang.org/p/ky75RbvoEz

38
程式討論版 / [Golang] built-in function copy
« 於: 2015-09-06 00:17 »
Go 的內建函數,針對 slice 做資料複製,類似 c 的 memcpy

原型:

代碼: [選擇]
func copy(dst, src []Type) int
如果成功複製會傳回複製的個數

dst src 可以在同一個 slice 內操作

dst src 可以指定開始與結束的位置

代碼: [選擇]
copy(a1[5:6], a1[8:])
/*
result: a1: [1 3 5 7 9 19 13]
src 指定要複製8開始到最後,但是 dst 指定只能複製到第5的位置,因此只有複製 19 過來
*/

copy 常用在移除元素(remove elements)
下面註解的部分是在同一個 slice 操作
a3 則是建立新的 slice 存放結果

Code:
代碼: [選擇]
  a1 := []int{1, 3, 5, 7, 9, 11, 13, 17, 19, 23}
  a2 := make([]int, 15, 30)
  fmt.Println("a1:", a1)
  fmt.Println("a2:", a2)

  copy(a2[10:], a1)
  fmt.Println("a2:", a2)

  //remove 11, 13, 17
  //copy(a1[5:], a1[8:])
  //a1 = a1[:7]
 
  a3 := make([]int, 7)
  copy(a3[:5], a1)
  copy(a3[5:], a1[8:])
  fmt.Println("a3:", a3)


Result:
引用
a1: [1 3 5 7 9 11 13 17 19 23]
a2: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
a2: [0 0 0 0 0 0 0 0 0 0 1 3 5 7 9]
a3: [1 3 5 7 9 19 23]

http://play.golang.org/p/6MQcr5lu7t

39
最近有兩個鍵盤方面的問題

1. backspace 鍵似乎會造成整個鍵盤崩潰,每次多按幾次 BS 鍵之後
不管再按什麼鍵都會瘋狂重覆

2. 另一個問題是這幾天出現的,就是鍵盤會突然失效
我接的鍵盤是無線小鍵盤,右邊有一個小觸控板
鍵盤失效時小觸控板卻還能正常使用

第1個問題我猜應該是 ssh X11 forwarding 的關係(第2個大概也是吧)
我用平板連線或是改用桌機連都會發生同樣情形
google 還沒找到相關討論
目前只能儘量不按 BS 鍵



40
go 有提供關閉 channel 的函數: close(ch)
在讀取時可以多一個變數取得 channel 的狀態

例如:

代碼: [選擇]
msg, ok := <- ch1
if ok {
  println(msg)
}

這樣可以避免去讀取一個已關閉的 channel
但奇怪的是,go 卻未提供判斷 channel 是否已關閉的功能
例如類似這樣的函數:

isClosed(ch1)

基於常久以來的習慣,總是會想在寫入前先做判斷
一直到目前的 1.5rc1 版,都還沒有這樣的函數
不過還有是其它方式可做到類似效果
只是不用 close(ch)
直接將這個 channel 設為 nil


代碼: [選擇]
package main

import (
  "fmt"
  "math/rand"
  "time"
)

const funcNum, gCountMax int = 20, 360

func main() {
  rand.Seed(time.Now().UTC().UnixNano())
  ch1, ch2 := make(chan string), make(chan string)

  for idx := 0; idx < funcNum; idx++ {
    go func(fid int) {
      fCount := 0
      for {
        if ch1 != nil {
          ch1 <- fmt.Sprintf(" [%v]: %v ", fid, fCount)
          fCount++
          if fCount > 18 {
            ch1 = nil
          }
          time.Sleep(time.Millisecond * time.Duration(rand.Intn(30)*5))
        } else {
          return
        }
      }
    }(idx)
  }

  gCount := 0
  rCount := 0
  go func() {
    defer func() { ch2 <- "Done!" }()
    for {
      select {
      case msg, ok := <-ch1:
        if ok {
          print(msg)
          rCount++
        }
        gCount++
        if gCount >= gCountMax {
          ch1 = nil
        }
      default:
        if ch1 == nil {
          return
        }
      }
    }
  }()
  msg := <-ch2
  fmt.Printf("\n%v, %s\n", rCount, msg)
}


if ch1 != nil {
  ch1 <- fmt.Sprintf(" [%v]: %v ", fid, fCount)
  .....

這邊在寫入 channel 前先判斷是否為 nil
當然,就不要再用 close() 關閉 channel


41
程式討論版 / [Golang] Wait for the goroutine end
« 於: 2015-08-11 19:25 »
goroutine 有個現象,在 main() 建立 goroutine 後,如果這個函數還沒跑完,
main() 並不會等它結束後才結束整個程式,看個例子

代碼: [選擇]
package main

func main() {
var count int64 = 0
go func() {
for idx := 0; idx < 200; idx++ {
count++
}
}()

println(count)
}

執行結果:

引用
$ go run ex041.go
0

for 迴圈根本就還沒跑到,整個程式就 game over
整理了幾個能讓 goroutine 確實跑完的方式

(1) 利用鍵盤輸入等待

代碼: [選擇]
import (
"fmt"
)

func main() {
var count int64 = 0
go func() {
for idx := 0; idx < 200; idx++ {
count++
}
}()

var in string
fmt.Scanln(&in)
println(count)
}

引用
result:
200

雖然可行,不過迴圈如果要跑很久,會因為按鍵盤時間快慢,迴圈也有可能不會完全跑完


(2) 利用 channel

代碼: [選擇]
func main() {
var count int64 = 0
c1 := make(chan bool)

go func() {
for idx := 0; idx < 200; idx++ {
count++
}
c1 <- true
}()
<-c1
println(count)
}

channel 型態不定要 bool,任何資料型態都可以,整數、字串甚至 struct 也可以

代碼: [選擇]
type MyType struct {
ID   int64
Name string
}

func main() {
var count int64 = 0
c1 := make(chan MyType)

go func() {
for idx := 0; idx < 200; idx++ {
count++
}
c1 <- MyType{}
}()
<-c1
println(count)
}

c1 目的只是要在接收資料時的等待效果。


(3) 使用 sync/WaitGroup

代碼: [選擇]
import (
"sync"
)

func main() {
var count int64 = 0
var wg sync.WaitGroup

wg.Add(1)
go func() {
defer wg.Done()
for idx := 0; idx < 200; idx++ {
count++
}

}()
wg.Wait()
println(count)
}

這個就比較清楚了,在使用 go 之前先告訴系統有一個 goroutine 要等待它跑完

defer wg.Done() 這行是告訴系統『我跑完嘍』

方式 1,2 適合單一 goroutine 或是數量不多時,當 goroutine 數量很多
sync/WaitGroup 就很好用,wg.Wait()會等到所有 goroutine 都結束才放行



42
程式討論版 / [Golang] Test & Benchmark 的寫法
« 於: 2015-08-10 17:39 »
go 提供的 test 與 benchmark 有3個限制,必需要依照這3個規則來做,這2兩個功能才跑得出來

1. 原始碼檔名必須以『 _b_test.go 』結尾,例如 getData_b_test.go

2. 測試的函數名必須 Test 或 Benchmark 開頭,至於之後的底線則可有可無,例如

   func TestgetData1(t *testing.T) {}
   func Test_getData1(t *testing.T) {}
   func BenchmarkgetData1(b *testing.B) {}
   func Benchmark_getData1(b *testing.B) {}

3. 如果要測試整個資料夾內的原始碼,則此資料夾的原始碼不能包含有任何的 main() 函數
   如果資料夾裡有 main() 則可改用單一檔案測試

假設現在要開發一個字串串接的功能,go 有3種方式可以串接字串
於是我們寫個測試碼來看看哪一種效率較高

src/strconcat/strconcat.go
(這個是我新開發的功能,不是測試碼,所以檔名不用加 _b_test)

代碼: [選擇]
package strconcat

import (
  "bytes"
)

func Strconcat1(str1, str2 string) string {
  return str1 + str2
}

func Strconcat12(str1, str2 string) {
  str1 += str2
}

func Strconcat13(str1, str2 string, str0 *string) {
  *str0 = str1 + str2
}

func Strconcat2(str1, str2 string, str0 *[]byte) {
  *str0 = []byte(str1)
  *str0 = append(*str0, str2...)
}

func Strconcat3(str1, str2 string, str0 *bytes.Buffer) {
  str0.WriteString(str1)
  str0.WriteString(str2)
}

接下來就要寫一個測試碼來跑這幾個函數

strconcat_b_test.go
(這個測試碼我放在目前工作資料夾內,不需要放在 src 裡)

代碼: [選擇]
package bmStrConcat

import (
  "bytes"
  "fmt"
  "testing"
  "strconcat"
)

var str1 string = "123456789012345678901234567890"
var str2 string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func TestStrConcat1(t *testing.T) {
  str := strconcat.Strconcat1(str1, str2)
  if str != "" {
    fmt.Println(str)
  }
}

func TestStrConcat13(t *testing.T) {
  str := ""
  strconcat.Strconcat13(str1, str2, &str)
  if str != "" {
    fmt.Println(str)
  }
}

func TestStrConcat2(t *testing.T) {
  var str []byte
  strconcat.Strconcat2(str1, str2, &str)
  if string(str) != "" {
    fmt.Println(string(str))
  }
}

func TestStrConcat3(t *testing.T) {
  var str bytes.Buffer
  strconcat.Strconcat3(str1, str2, &str)
  if str.Len() >0 {
    fmt.Println(str.String())
  }
}

func BenchmarkStrConcat1(b *testing.B) {
  str0 := ""
  for idx := 0; idx < b.N; idx++ {
    str0 = strconcat.Strconcat1(str1, str2)
  }
  fmt.Sprintf("%v", str0)
}

func BenchmarkStrConcat12(b *testing.B) {
  for idx := 0; idx < b.N; idx++ {
    strconcat.Strconcat12(str1, str2)
  }
}

func BenchmarkStrConcat13(b *testing.B) {
  str0 := ""
  for idx := 0; idx < b.N; idx++ {
    strconcat.Strconcat13(str1, str2, &str0)
  }
}

func BenchmarkStrConcat2(b *testing.B) {
  var str0 []byte
  for idx := 0; idx < b.N; idx++ {
    strconcat.Strconcat2(str1, str2, &str0)
  }
}

func BenchmarkStrConcat3(b *testing.B) {
  var str0 bytes.Buffer
  for idx := 0; idx < b.N; idx++ {
    str0.Reset()
    strconcat.Strconcat3(str1, str2, &str0)
  }
}


Testxxxxx 的部分主要是查看新函數跑出來的結果是否正確
不一定要像上面那樣寫,也可以改成這樣

代碼: [選擇]
var str3 string = str1 + str2

func TestStrConcat1(t *testing.T) {
  str := strconcat.Strconcat1(str1, str2)
  if str != "" && str == str3 {
    fmt.Println("1 OK!")
  }
}

func TestStrConcat13(t *testing.T) {
  str := ""
  strconcat.Strconcat13(str1, str2, &str)
  if str != "" && str == str3 {
    fmt.Println("13 OK!")
  }
}

func TestStrConcat2(t *testing.T) {
  var str []byte
  strconcat.Strconcat2(str1, str2, &str)
  if string(str) == str3 {
    fmt.Println("2 OK!")
  }
}

func TestStrConcat3(t *testing.T) {
  var str bytes.Buffer
  strconcat.Strconcat3(str1, str2, &str)
  if str.String() == str3 {
    fmt.Println("3 OK!")
  }
}


Benchmark 的部分就是用迴圈去呼叫新函數...

執行方式跟原來差不多,只是 run 改成 test,並加個選項

引用
$ go test strconcat_b_test.go -bench=.
1 OK!
13 OK!
2 OK!
3 OK!
PASS
BenchmarkStrConcat1-4    10000000          205 ns/op
BenchmarkStrConcat12-4   10000000          218 ns/op
BenchmarkStrConcat13-4   10000000          225 ns/op
BenchmarkStrConcat2-4     5000000          331 ns/op
BenchmarkStrConcat3-4    30000000           56.4 ns/op
ok     command-line-arguments   10.918s

-bench=. 表示測試所有的 Textxxx() 與 Benchmarkxxx()

有時候只想看某部分的結果,例如只跑 StrConcat3 的部分,指令可以這樣下

引用
$ go test strconcat_b_test.go -run=.*t3 -bench=.*t3
3 OK!
PASS
BenchmarkStrConcat3-4   30000000           52.4 ns/op
ok     command-line-arguments   1.642s

跑 StrConcat2 跟 StrConcat3 的話

引用
$ go test strconcat_b_test.go -run=.*t[23] -bench=.*t[23]
2 OK!
3 OK!
PASS
BenchmarkStrConcat2-4    5000000          315 ns/op
BenchmarkStrConcat3-4   30000000           52.4 ns/op
ok     command-line-arguments   3.551s

或是跑 1,3

引用
$ go test strconcat_b_test.go -run=.*t[13] -bench=.*t[13]
1 OK!
13 OK!
3 OK!
PASS
BenchmarkStrConcat1-4    10000000          200 ns/op
BenchmarkStrConcat12-4   10000000          190 ns/op
BenchmarkStrConcat13-4   10000000          199 ns/op
BenchmarkStrConcat3-4    30000000           51.7 ns/op
ok     command-line-arguments   8.193s

or

引用
$ go test strconcat_b_test.go -run=.*t[13]$ -bench=.*t[13]$
1 OK!
3 OK!
PASS
BenchmarkStrConcat1-4   10000000          199 ns/op
BenchmarkStrConcat3-4   30000000           52.1 ns/op
ok     command-line-arguments   3.834s

t[13]$ 表示結尾,所以 strconcat12, strconcat13 就不會跑


有人說,自己寫 package 之後一定要加 test 的碼
其實看個人啦,如果是要公開給大家用的,那當然就需要囉
最好連 benchmark 的部分都直接提供
如果只是自己用,那就看自己嚕!^_____^




43
程式討論版 / [Golang] channel & for & select
« 於: 2015-08-06 18:15 »
今天看了這篇

Golang channels tutorial

算是這兩週所看過相關文章中,對 channel 使用有比較簡單清楚的說明

不過很可惜最後還是少了一種情況,就是當 channel 需要發送的資料數不確定時
文章最後範例是這樣:

代碼: [選擇]
package main

import (
"fmt"
"time"
)

func getMesgChannel(msg string, delay time.Duration) <-chan string {
c := make(chan string)
go func() {
for i := 1; i <= 3; i++ {
c <- fmt.Sprintf("%s, %d", msg, i)
time.Sleep(time.Millisecond * delay)
}
}()
return c
}

func main() {
c1 := getMesgChannel("001", 300)
c2 := getMesgChannel("002", 150)
c3 := getMesgChannel("003", 10)

for i := 1; i <= 9; i++ {
select {
case msg := <-c1:
fmt.Println(msg)
case msg := <-c2:
fmt.Println(msg)
case msg := <-c3:
fmt.Println(msg)
}
}
}

實際上在很多場合,如果 sender 不確定會發送多少資料出來
在接收端通常會用無窮迴圈來接收資料,例如:

代碼: [選擇]
  for {
select {
.....
}
}

但是這真的會造成無窮迴圈啊,發送端如果都停止送資料

fatal error: all goroutines are asleep - deadlock!

在 getMesgChannel() for{} 結束時關閉 channel 呢?
很可惜,一樣會造成 deadlock

我自己想到的方式是在 select 加一條 time.After的 case
超過多久時間沒收到任何訊息便結束迴圈

代碼: [選擇]
  for {
select {
case msg := <-c1:
fmt.Println(msg)
case msg := <-c2:
fmt.Println(msg)
case msg := <-c3:
fmt.Println(msg)
case <-time.After(time.Millisecond * 500):
fmt.Println("Done!")
break
}
}

不過這裡的 break 只會對 select 區塊有作用
還是無法跳出 for 迴圈,結果就是一直印出『Done!』

有兩個方式可以跳出 for 迴圈,一個是設變數來判斷
另一個是將 break 改成 return

代碼: [選擇]
  done := false
for {
select {
    ..... 
case <-time.After(time.Millisecond * 500):
fmt.Println("Done!")
return
done = true
}
if done {
break
}
}

or
代碼: [選擇]
    case <-time.After(time.Millisecond * 500):
fmt.Println("Done!")
return
完整範例:

或點這裡

代碼: [選擇]
package main

import (
"fmt"
"time"
)

func getMesgChannel(msg string, count int, delay time.Duration) <-chan string {
c := make(chan string)
go func() {
for i := 1; i <= count; i++ {
c <- fmt.Sprintf("%s, %d", msg, i)
time.Sleep(time.Millisecond * delay)
}
}()
return c
}

func main() {
c1 := getMesgChannel("001", 5, 300)
c2 := getMesgChannel("002", 8, 200)
c3 := getMesgChannel("003", 13, 10)

done := false
for {
select {
case msg := <-c1:
fmt.Println(msg)
case msg := <-c2:
fmt.Println(msg)
case msg := <-c3:
fmt.Println(msg)
case <-time.After(time.Millisecond * 500):
fmt.Println("Done!")
      done = true
//return
}
if done {
break
}
}
}

執行結果:

引用
$ time go run ex038.go
002, 1
003, 1
001, 1
003, 2
003, 3
003, 4
003, 5
003, 6
003, 7
003, 8
003, 9
003, 10
003, 11
003, 12
003, 13
002, 2
001, 2
002, 3
002, 4
001, 3
002, 5
001, 4
002, 6
002, 7
001, 5
002, 8
Done!

real   0m2.411s
user   0m0.552s
sys   0m0.284s


44
在語法上, goroutine 不能有傳回值,或者換個比較正確的說法
在 『go func()』這個述中,不能有等號出現,所以就算函數有傳回值
在函數結束後返回的值會直接被丟棄

代碼: [選擇]
import (
"fmt"
)

func getInt() int {
return 12345
}

func main() {
res := 0
go res = getInt()
fmt.Println(“res:”, res)

}
 

這裡編譯就過不了

引用
$ go run ex032.go
# command-line-arguments
./ex032.go:12: syntax error: unexpected =, expecting ( or . or [

但是有傳回值並不會不給『go』

代碼: [選擇]
func main() {
go getInt()
fmt.Println("Done!")

}

就算函數有傳回值,其實還是可以『go』
只是無法接收傳回值,直接忽略了

引用
$ go run ex032.go
Done!

如果無論如何,一定要得到那個傳回值呢?!
那就改用 channel 來傳吧

代碼: [選擇]
func getInt(c chan int) {
c <- 12345
}

func main() {
c := make(chan int)
go getInt(c)
res := <-c
fmt.Println("res:", res)
}

引用
$ go run ex032.go
res: 12345

^_____^

45
早上在修改一些 c++ 的東西,發現一個有趣的現象

下面是測試碼:

代碼: [選擇]
#include <iostream>
#include "microtime.h"

void swap(int &x, int &y) {
int tmp(x);
x = y;
y = tmp;
}

const int loopMax = 50000001;

int main() {
  int x = 24578, y = 2982;
  double t1 = microtime();
  for (int idx=0; idx<loopMax; ++idx) {
    swap(x, y);
  }
  t1 = microtime(t1);
  std::cout << "x, y = " << x << ", " << y
            << " [" << t1*1000 << "ms]\n";

  return 0;
}


本來是用 clang++ -O3 編譯,發現跑出來的時間怪怪的
於是就加 -S 看一下編出來的 asm code

代碼: [選擇]
fdivs .LCPI1_0(%rip)
    movl $50000002, %ecx         # imm = 0x2FAF082
    .align 16, 0x90
.LBB1_1:                                # =>This Inner Loop Header: Depth=1
    addl $-26, %ecx
    jne .LBB1_1
# BB#2:

哈~~~~~ 原來是騙局啦~~~
迴圈數還會偷偷加1呢~ ^_^

然後 cout 的地方
就直接將編譯器預估的結果印出來

 
代碼: [選擇]
    movl $2982, %esi             # imm = 0xBA6
    callq _ZNSolsEi
    movq %rax, %rbx
    movl $.L.str1, %esi
    movl $2, %edx
    movq %rbx, %rdi
    callq _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    movl $24578, %esi            # imm = 0x6002
    movq %rbx, %rdi
    callq _ZNSolsEi

所以根本就沒有真的跑 swap
連迴圈也是偷工減料來跑 XD

後來我改用 -O1 來編譯看看,另外也用 g++ 編

clang -O1:
 
代碼: [選擇]
    movl $50000001, %ebp         # imm = 0x2FAF081
    callq _Z9microtimee
    fstpt 16(%rsp)                # 10-byte Folded Spill
    leaq 60(%rsp), %r14
    leaq 56(%rsp), %rbx
    .align 16, 0x90
.LBB2_1:                                # =>This Inner Loop Header: Depth=1
    movq %r14, %rdi
    movq %rbx, %rsi
    callq _Z4swapRiS_
    decl %ebp
    jne .LBB2_1
# BB#2:

clang -O1 就有正常跑迴圈和呼叫 swap()
不過卻沒有自動將 swap() 編成 inline


g++ -O1:
代碼: [選擇]
    movl $50000001, %eax
    movl $24578, %ebx
    movl $2982, %ebp
    jmp .L12
.L13:
    movl %ebp, %edx
    movl %ebx, %ebp
    movl %edx, %ebx
.L12:
    subl $1, %eax
    jne .L13
   
.L13 ~ .L12 之間這3行就是實際執行 swap() 的動作

g++ -O3:
代碼: [選擇]
    movl $50000001, %eax
    fldl 40(%rsp)
    popq %rcx
    .c 72
    popq %rsi
    .cfi_def_cfa_offset 64
    jmp .L14
    .p2align 4,,10
    .p2align 3
.L15:
    movl %ebp, %edx
    movl %ebx, %ebp
    movl %edx, %ebx
.L14:
    subl $1, %eax
    jne .L15

swap() 的動作是在 .L15 ~ .L14

g++ -O1 或 -O3 都會正常編出迴圈
而且也會自動將 swap 編成 inline

下面是跑出來的結果

引用
$ ./ex044-clang++O1 && ./ex044-clang++O3 && ./ex044-g++O1 && ./ex044-g++O3
x, y = 2982, 24578 [1081.17ms]
x, y = 2982, 24578 [3.09399ms]
x, y = 2982, 24578 [402.601ms]
x, y = 2982, 24578 [339.092ms]

g++ 將 swap() 編成 inline
執行時就減少函數呼叫動作
因此會比 clang++ -O1 的碼快


46
加~油~!!加~油~!!! *\(^_^)/*

47
已前有玩過 PHP 文章相似度計算的功能
相似度超過多少%就不給貼文 ...

48
php 用習慣了,換個語言來開發總是會想說最好也能夠有支援類似 php 的 hash table
還好 golang 雖然沒有直接支援,不過可以很簡單地定義一個類似的型態來用
例如:

代碼: [選擇]
<?php
error_reporting(0);

$mVal1["k01"] = 12345;
$mVal1["k02"] = "abcdefg";
$mVal1["k03"]["k31"] = 54321;
$mVal1["k03"]["k32"] = "資料123";

var_dump($mVal1);
echo "\$mVal1['k04']['k41']: {$mVal1['k04']['k41']}\n";
?>

在 golang 可以這樣來用

代碼: [選擇]
package main

import (
"fmt"
)

type hash map[string]interface{}

func main() {
mVal1 := make(hash)

mVal1["k01"] = 12345
mVal1["k02"] = "abcdefg"
mVal1["k03"] = make(hash)
mVal1["k03"].(hash)["k31"] = 54321
mVal1["k03"].(hash)["k32"] = "資料123"

fmt.Println("mVal1:", mVal1)
fmt.Println("mVal1[k01]:", mVal1["k01"])
fmt.Println("mVal1[k03]:", mVal1["k03"])
fmt.Println("mVal1[k03][k32]:", mVal1["k03"].(hash)["k32"])
fmt.Println("mVal1[k03][k33]:", mVal1["k03"].(hash)["k33"])

  fmt.Println("mVal1[k04][k42]:", mVal1["k04"].(hash)["k42"])
}

hash 這個自己定義的型態在使用上就有類似 php 陣列的效果
不過,不小心用到未定義過的 key 就掛掉了,像這樣

引用
$ go run ex030.go
mVal1: map[k01:12345 k02:abcdefg k03:map[k31:54321 k32:資料123]]
mVal1[k01]: 12345
mVal1[k03]: map[k31:54321 k32:資料123]
mVal1[k03][k32]: 資料123
mVal1[k03][k33]: <nil>
panic: interface conversion: interface is nil, not main.hash

goroutine 1 [running]:
main.main()
   /home/cpp/go/ex030.go:25 +0xcfe

golang 不會像 php 那樣,使用未定義過的變數就直接空白跳過

雖然麻煩,不過還是有解法:
 
代碼: [選擇]
  //fmt.Println("mVal1[k04][k42]:", mVal1["k04"].(hash)["k42"])
 
  if k04, ok := mVal1["k04"]; ok {
fmt.Println("mVal1[k04][k42]:", mVal1["k04"].(hash)["k42"])
fmt.Println("k04.[k41]", k04.(hash)["k41"])
} else {
mVal1["k04"] = make(hash)
mVal1["k04"].(hash)["k42"] = "新增資料567"
    fmt.Println("mVal1[k04][k41]:", mVal1["k04"].(hash)["k41"])
fmt.Println("mVal1[k04][k42]:", mVal1["k04"].(hash)["k42"])
}

引用
$ go run ex030.go
mVal1: map[k01:12345 k02:abcdefg k03:map[k32:資料123 k31:54321]]
mVal1[k01]: 12345
mVal1[k03]: map[k31:54321 k32:資料123]
mVal1[k03][k32]: 資料123
mVal1[k03][k33]: <nil>
mVal1[k04][k41]: <nil>
mVal1[k04][k42]: 新增資料567

---
在用 json 字串 decode 轉成 map 後就要很小心使用這個 map
不然碰到沒有預期中該有的 key 就會像上面那樣掛了
^__________^

49
因為剛好看到 go1.5b2 已完成 9x%,想說就抓下來試一下
意外發現 1.5b2 編出來的碼執行效能真的快了不少
這是我原來用的測試碼:

代碼: [選擇]
package main

import (
"fmt"
"sync"
"runtime"
)

const loopMax = 100000
var wg sync.WaitGroup
var goCount, allDone int64 = 0, 0
var c chan bool = make(chan bool, 1)

func addCount() {
defer wg.Done()
for ok := range c  {
if ok {
goCount++
}
if allDone == 0 {
close(c)
}
}
}

func func1(id int) {
defer wg.Done();
//defer close(c)
var str1, str2 string = "在資料序列(Data sequence)中隨機找一元素為定界點(Pivot)," +
"然後讓序列的其他元素與定界點比較,比定界點小的元素放左邊,大的放右邊。在定界點左邊子序列" +
"和右邊子序列,再以相同的方式處理,直到整個序列排序完畢。", ""

for idx:=0; idx<loopMax; idx++ {
str2 = fmt.Sprintf("[%v]%v", id, str1)
c <- true
}
allDone--
fmt.Println(str2)
}

func main() {
//runtime.GOMAXPROCS(2)
runtime.GOMAXPROCS(runtime.NumCPU())

allDone = 4

for idx:=0; idx<4; idx++ {
wg.Add(1)
go func1(idx)
}

defer func() {
fmt.Println(goCount)
}()

wg.Add(1)
go addCount()
wg.Wait()
}

開4個 goroutine 加 4核心來跑,結果如下

引用
$ go version
go version go1.4.2 linux/amd64
$ go build -o ex022-01 ex022.go

$ go version
go version go1.5beta2 linux/amd64
$ go build -o ex022-02 ex022.go

$ time ./ex022-01 && time ./ex022-02
[3]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[2]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[1]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[ 0 ]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
400000

real   0m3.922s
user   0m4.379s
sys   0m5.404s
[3]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[2]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[1]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[ 0 ]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
400000

real   0m1.258s
user   0m1.466s
sys   0m0.496s

其實本來是沒有用到 fmt.Sprintf(),加了這個函數後發現差更多

另外我把前兩天玩的碼也拿測了一下,是 json 的編碼與解碼


代碼: [選擇]
package main
import (
"fmt"
"yHash"
)

func main() {
var vecVal1 [5]int = [5]int{1, 2, 3, 4, 5} // array
var vecVal2 []int = []int{1, 2, 3, 4, 5} // slice

hash1 := make(yHash.Hash)

hash1["abc"] = 12345
hash1["def"] = "abcdefghijk"
hash1["vec1"] = vecVal1
hash1["vec2"] = vecVal2
//hash1["subHash"] = make(yHash.Hash)
hash1["subHash"] = yHash.Hash {
"編號1": "9456234534254",
"編號2": 9456234534254,
"編號3": 9456234,
"編號4": 945623,
"單位":  "研發",
"專長1": yHash.Hash{
"第一": "吃飯",
"第二": "睡覺",
"第三": "玩電動",
"第四": "看動漫",
},
}

hash1["subHash"].(yHash.Hash)["專長2"] = yHash.Hash{
"S01" : "C++",
"S02" : "PHP",
"S03" : "Java",
"S04" : "Perl",
"S05" : "Golang",
"S06" : "Python",
"S07" : "ShellScript",
"S08" : "JavaScript",
"S09" : "HTML/CSS",
"S10" : "Pascal",
}

fmt.Println(hash1)
fmt.Println(hash1["subHash"].(yHash.Hash)["專長1"].(yHash.Hash)["第一"])

var loopMax int = 100000
var tDatas string
for idx:=0; idx<loopMax; idx++ {
tDatas = hash1.JsonEncode()
}

fmt.Println(tDatas)
fmt.Println("\nEncode OK!\n")

var hash2 yHash.Hash
for idx:=0; idx<loopMax; idx++ {
hash2.JsonDecode(tDatas)
}
fmt.Println("Decode OK!\n")

id21, ok := hash2["subHash"].(map[string] interface{})["編號2"]
var id22 int64
if ok {
id22 = yHash.GetJsonInt(id21)
hash2["subHash"].(map[string] interface{})["編號2"] = id22
}
hash2["subHash"].(map[string] interface{})["編碼"] = 238462.1238478349
fmt.Println(hash1, "\n\n", id21, id22)
fmt.Printf("\n%v\n", hash2)

hash1.Dump()
hash2.Dump()
}


引用
$ time ./ex020-01 && time ./ex020-02
.....

real   0m10.971s
user   0m12.318s
sys   0m3.005s

.....

real   0m8.012s
user   0m9.383s
sys   0m2.916s

跑出來結果 1.5b2 也快了不少!!

---
也許真的有那麼一天
當 golang 與 c++ 執行速度並駕齊驅時.....
^_____________^

50
應該不會每次 du 都要花很長時間吧
每次 du 後都會有 cache
除非是清 cache 或  ram 不夠

每次 du 排除不必要的資料夾啦、網路資料夾啦.....

51
記得之前好像有開啟限定連續發文時間啊

最近真的好多洗版廣告  =___________=|||

52
在 terminal 開啟編輯器後
terminal 一直會印出一些警告或是錯誤訊息
像這樣.....

$
(sublime_text:6091): GLib-CRITICAL **: Source ID 780 was not found when attempting to remove it

(sublime_text:6091): GLib-CRITICAL **: Source ID 3607 was not found when attempting to remove it

(sublime_text:6091): GLib-CRITICAL **: Source ID 4159 was not found when attempting to remove it

雖然不會影響工作,不過看起來很礙眼 XD
想到在設定 cron 常用到的方式 就試了一下

$ subl& > /dev/null 2<&1

好像沒效,改了一下

$ subl > /dev/null 2<&1&

這樣就 OK 了
那些訊息就不會再出現 ^_____^

53
今天在玩 Go 解 Sqrt() 碰到一個問題(今天第一次玩 Go,有誤請指正 ^__^)

Code:
代碼: [選擇]
package main
import (
  "fmt"
  "math"
)

var step int = 0;
var z float64 = 1.0;
var s float64 = 0.0;

func Sqrt(x float64) float64 {
  if step >= 12 {
    return x
  }
 
  if s == 0 {
    s = x
  }
 
  z = (z + s/z) / 2
  step++
  fmt.Println(z, x, step)
  Sqrt(z)
  return z
}

func main() {
  x := 12345.0;
 
  fmt.Println("Sqrt:");
  fmt.Println(Sqrt(x), "\n");

  fmt.Println(math.Sqrt(x));
}

Result:
引用
Sqrt:
6173 12345 1
3087.499919002106 6173 2
1545.7491498369006 3087.499919002106 3
776.8677842956971 1545.7491498369006 4
396.37925958974336 776.8677842956971 5
213.76183709549736 396.37925958974336 6
135.75651245108165 213.76183709549736 7
113.34568823712989 135.75651245108165 8
111.13014281250861 113.34568823712989 9
111.10805770848404 111.13014281250861 10
111.10805551354053 111.10805770848404 11
111.1080555135405 111.10805551354053 12
111.1080555135405

111.1080555135405

---
雖然有弄出來,只是有一點很不滿意,就是 Go 竟然未支援靜態變數!!!
所以上面有三個變數要宣告為全域變數,這樣真的很危險啊!!

後來看到有支援 closure 功能,於是就試了一下改成如下

Code:
代碼: [選擇]
func Sqrt2(x float64) float64 {
  step := 0;
  z := 1.0;
  s := x;
  var Sqrt func(float64) float64
 
  Sqrt = func(x float64) float64 {
    if step >= 12 {
      return x
    }
   
    z = (z + s/z) / 2
    step++
    fmt.Println(z, x, step)
    Sqrt(z)
    return z
  }
 
  return Sqrt(s);
}

func main() {
  x := 12345.0;
 
  fmt.Println("Sqrt:");
  fmt.Println(Sqrt(x), "\n");
 
  fmt.Println("Sqrt2:");
  fmt.Println(Sqrt2(x), "\n");
 
  fmt.Println(math.Sqrt(x));
}

Result:
引用
Sqrt2:
6173 12345 1
3087.499919002106 6173 2
1545.7491498369006 3087.499919002106 3
776.8677842956971 1545.7491498369006 4
396.37925958974336 776.8677842956971 5
213.76183709549736 396.37925958974336 6
135.75651245108165 213.76183709549736 7
113.34568823712989 135.75651245108165 8
111.13014281250861 113.34568823712989 9
111.10805770848404 111.13014281250861 10
111.10805551354053 111.10805770848404 11
111.1080555135405 111.10805551354053 12
111.1080555135405

這樣就可以將原來的全域變數改成區域變數
當然,執行結果完全相同 ^____^



54
這真有繼續深入研究的價值 ...

小弟習慣使用同一桌面 , 沒做完的事就一直開著
從桌機 , NB , server 本機 , 都能繼續未完的工作
所以是用 vnc over rdp

如此再與 citrix 做聯想 ..
ssh forwarding x11 是模擬當下最輕便的圖形而非原本桌面環境
rdp 擁有完整環境
搭配 winexe 可跑 ms 程式 (mac 呢? ...)
useradd 比 clone vm 簡便

...


ps ..
用平板寫程式 , 不會綁手綁腳的嗎 ?

哈~~沒錯,就是這樣啦!! ^_____________^
這兩天還試過直接在 android 叫出遠端程式窗視
雖然是有成功顯示啦,但是....怎麼說呢
顯示效果感覺就像回到最原始 x-window 桌面環境
如果只是這樣那到還好,只不過視窗反應太慢就用不下去了

目前在構想
看能不能將  tinycore 灌到平板裡
只要有基本桌面環境+ssh 就好
這樣就可以真的直接用平板連線了

---
ps:
平板+LCD螢幕+外接鍵盤滑鼠.....
就寫程式來說,配備功能已不輸給PC了
^_______^

55
又有一個小問題

本來用平板在VM(本機) ssh 登入 jper ,也啟動了 ibus
後來換開桌機使用,而 VM(本機) 的 jper 連線忘了登出
我在桌機又另外開 ssh 登入 VM 的 jper 時
就發現沒在我現在這個連線啟動 ibus
也無法使用 VM 本機登入的 ibus
也就是說,在不同機器登入就要跑自己的 ibus
然後要避免同一台機器重覆登入時就不要重覆啟動
分析了一下能用到的資料...(env, who, ps)
下面是最後修改的碼 ^___^


代碼: [選擇]
IBUS_ISRUN=""
FROM_IP=`echo $SSH_CONNECTION|awk '{print $1}'`
for pts in `ps axu|grep "^${USER}.*[i]bus-daemon"|awk '{print $7}'`; do
  IBUS_ISRUN=`who |grep "^${USER}.*${pts}.*\(${FROM_IP}\)"|wc -l`
done

if [[ "$IBUS_ISRUN" = "" || "$IBUS_ISRUN" -eq 0 ]]; then
  /usr/bin/ibus-daemon --xim&
  echo "ibus starting.....[OK]"
fi

56
 今天把啟動 ibus 加到 .bashrc
不過要避免重覆登入時可能也會重覆啟動
所以用 ps 過濾了一下

代碼: [選擇]
IBUS_ISRUN=`ps axu|grep "^${USER}.*[i]bus-daemon"`
if [ "$IBUS_ISRUN" = "" ]; then
 /usr/bin/ibus-daemon --xim&
fi

登出時因為有程式在背景跑,會有卡住的現象
直接按一下 ctrl-c 就可以了 ^_____^

57
這樣無法開 gui 程式吧

引用
$ su cpp
cpp@:~$ gedit&
[1] 18755
cpp@:~$
No protocol specified
No protocol specified
Cannot open display:

而且用 ssh -X 還可以把遠端抓到自己桌面來顯示
所以這整個工作環境是兩部主機還是一部?

如果是一部,應該還是有可以不透過 SSH 的方案才是

本來是一台PC桌機+一台跑VM的 server
最近正在嘗試用平板連VM的桌面來工作
所以目前大部分是平板+VM在跑
用平板+VM算是在同一個環境
如果開桌機的話就是兩個系統


58
剛剛碰到一個小問題

無法輸入中文

雖然有叫出 ibus 輸入界面
不過這個界面是桌面這個 user 的

還好解決方式也很簡單
用登入的 user 另外啟動 ibus

$ /usr/bin/ibus-daemon --xim&

右上角就會出現另一個 ibus 圖示
先用滑鼠右鍵點新的圖示設定按鍵
然後就可以直接輸入中文字串了
^______^

59
補張圖



這張是 ssh -X 登入遠端後跑 java gui
標題列後面會顯示主機名

60
這樣無法開 gui 程式吧

引用
$ su cpp
cpp@:~$ gedit&
[1] 18755
cpp@:~$
No protocol specified
No protocol specified
Cannot open display:

而且用 ssh -X 還可以把遠端抓到自己桌面來顯示


頁: 1 [2] 3 4 ... 164