沉静如v 乐观向阳 http://www.tfdwme.live 本来无一?何处惹尘?/description> zh-CN Sun, 13 Oct 2019 15:42:02 +0000 python的try闭包作用域的问题 http://www.tfdwme.live/post/4f1b5dc7.html http://www.tfdwme.live/post/4f1b5dc7.html#comments http://www.tfdwme.live/post/4f1b5dc7.html

0x1:

python的try, except 很给力, 在有一些需要捕捉异常的场景下,能够安装异常的类别来q行特定的操作,假如说现在我们有一个场景是“无Z生什么异常,我们都有一个ȝ捕捉逻辑Q这U情况下Q我们就要注意try的闭包作用域问题?/p>

0x2Q直接上码:


def allCatch(func):
  def wrapper(*args, **kwargs):
    try:
      ret = func(*args, **kwargs)
      return ret
    except Exception as e:
      print "[allcatch] ------------------- ", e.message

  return wrapper



def foo():
  l = [0, 1, 2]
  li = l[9]
  print li


@allCatch
def main():
  foo()


if __name__ == "__main__":
  main()

上面的这个代码,在main里面执行foo能捕捉到ȝ异常Q但是我们现实中的逻辑可能会是下面q样


def allCatch(func):
  def wrapper(*args, **kwargs):
    try:
      ret = func(*args, **kwargs)
      return ret
    except Exception as e:
      print "[allcatch] ------------------- ", e.message

  return wrapper



def foo():
  l = [0, 1, 2]
  li = l[9]
  print li

def foo2():
  try:
    foo()
  except:
    print "foo2 except"

@allCatch
def main():
  foo2()


if __name__ == "__main__":
  main()


上面的代码运行的l果是 > foo2 except

如我们所见, 如果在main里面有另外的函数也执行了try捕捉异常Q那么main本n的try是无效的Q也p不到我们要的目的了。所以我们要注意try本n的闭包作用域的问?/p>

0x3 的用姿?/h3>
  • 我们的核心流E函敎ͼ也就是我们想捕捉的主要流E所在的函数Q,我们在q个函数上进行异常捕捉就行,比如上面的例子,其实我们可以Ҏ

@allCatch
def foo():
  l = [0, 1, 2]
  li = l[9]
  print li


def foo2():
  foo()

def main():
  foo2()


if __name__ == "__main__":
  main()

因ؓ我们的主逻辑是在 foo()函数Q?所以比较徏议的做法是把我们的异常捕捉攑֜q些我们需要关注,有可能生异常的函数M上,那么问题又来了,假如我有好几个这Ld数怎么办?那就全部加上。。。?)Q所以就要封装好我们的代码,不要没事写那么多垃圾代码才是王道?/p>

本文链接Q?a href="http://www.tfdwme.live/post/4f1b5dc7.html">http://www.tfdwme.live/post/4f1b5dc7.htmlQ?a href="http://www.tfdwme.live/post/4f1b5dc7.html#comments">参与评论

]]> golang的全局声明的生命周?/title> <link>http://www.tfdwme.live/post/369c0df7.html</link> <comments>http://www.tfdwme.live/post/369c0df7.html#comments</comments> <guid>http://www.tfdwme.live/post/369c0df7.html</guid> <description> <![CDATA[<blockquote> <h3 id="toc_0">场景:</h3> <p>当我们要q行redis操作或者其他中间g操作的时候,Z发h务端的连接,我们会在main函数外先建立q接Q以减少服务端的q接ơ数</p> <h3 id="toc_1">真相Q?/h3> <p>事实上,很多中间件的q接只是一个语法声明,其实q没有进行真正的q接Q比如下面的代码</p> <pre><code class="language-golang">package main import ( "fmt" "github.com/garyburd/redigo/redis" "github.com/spf13/cast" "math/rand" "time" ) var ( rds, errxx = redis.Dial("tcp", "1.1.1.1:3333") ) func Do(i int) { fmt.Println("开始进行redis操作...") act, err := rds.Do("SET", "name" + cast.ToString(i), i) fmt.Println(act, "--------", err) } func main() { ticker := time.NewTicker(3 * time.Second) defer ticker.Stop() for { select { case <-ticker.C: Do(rand.Intn(1000)) } } } </code></pre> <p>事实上每一个操作redis的时候,都会对redis重新发v一ơ连接,q没有v到减连接的作用</p> <h3 id="toc_2">验证</h3> <p>q行上面的程序, 然后观察redis的数据写入, 在写入一些数据之后,我们停止redis的服务,E序׃报错</p> <pre><code>use of closed network connection </code></pre> <p>可见即是放在main函数外的中间件句? 也只是一个声明(redisQ?mysql{都是,其他q没试Q,q没有进行真正的q接Q所以要减少发vq接的次敎ͼq是乖乖的用q接池吧?/p> <p>本文链接Q?a href="http://www.tfdwme.live/post/369c0df7.html">http://www.tfdwme.live/post/369c0df7.html</a>Q?a href="http://www.tfdwme.live/post/369c0df7.html#comments">参与评论 </a></p>]]> </description> </item> <item> <title>golang协程闭包数据陷阱 http://www.tfdwme.live/post/983f7411.html http://www.tfdwme.live/post/983f7411.html#comments http://www.tfdwme.live/post/983f7411.html

0x1

我们在写协程E序的时候,l常会碰C个场景就是我们要分发执行dl不同的goroutineQ简Ugor)Q然后再把各个gor的处理结果汇总v来,q个时候就要注意gor的数据污染问题,我们可以通过闭包来防范各个gor之间的数据污?/p>

0x2

下面的一个gor之间数据互相污染的范?/p>


func main() {
  setMem := make(map[int]int)
  wg := sync.WaitGroup{}
  lk := sync.RWMutex{}

  for i := 0; i < 10; i++ {    // 1
    wg.Add(1)
    
    go func(wg *sync.WaitGroup) {    // 2
      fmt.Println("i ---- ", i)
      defer wg.Done()
      lk.Lock()
      setMem[i] = i * 2
      lk.Unlock()
    }(&wg)
    
  }

  wg.Wait()
  fmt.Println("setMem 长度?----------", len(setMem))
  fmt.Println("setMem done ... ")
}

q个的运行结果ƈ非如我们所惻I汇M10?gor的处理结果到 setMem q个map中去


setMem 长度?---------- 1
setMem done ... 

原因分析

注释1 因ؓmain gor ?go func 是同时在q行的, 所以main在赋值给 i 的同Ӟ 2 接收?i 的值ƈ没有锁定 i Q?而是接收到最新的for循环的?/p>

注释2 没有一个安全的内存区域储存传给当前 gor ?i |所以造成数据污染

0x3

用闭包的原理去解册个问?/p>


func setM(wg *sync.WaitGroup, lk *sync.RWMutex, setMemx *map[int]int, i int) {
  defer wg.Done()
  fmt.Println("i ---- ", i)
  (*setMemx)[i] = i * 2
}

func main() {
  setMemx := make(map[int]int)
  wg := sync.WaitGroup{}
  lk := sync.RWMutex{}
   
  for i := 0; i < 10; i++ {          // 1
    wg.Add(1)
    setM(&wg, &lk, &setMemx, i)      // 2
  }

  wg.Wait()
  fmt.Println("setMem 长度?----------", len(setMemx))
  fmt.Println("setMem done ... ")
}

q行l果


setMen 长度?---------- 10
setMem done ... 

注释1 1 处依然是通过循环赋予 i ?注释2 2通过声明独立的funcQ来q行内存数据作用域锁定,闭包的原理,防止数据污染

所以运行的l果如我们所?/p>

本文链接Q?a href="http://www.tfdwme.live/post/983f7411.html">http://www.tfdwme.live/post/983f7411.htmlQ?a href="http://www.tfdwme.live/post/983f7411.html#comments">参与评论

]]>
2019M清单 http://www.tfdwme.live/post/c65ced15.html http://www.tfdwme.live/post/c65ced15.html#comments http://www.tfdwme.live/post/c65ced15.html
  • [x] Concurrency in Go

本文链接Q?a href="http://www.tfdwme.live/post/c65ced15.html">http://www.tfdwme.live/post/c65ced15.htmlQ?a href="http://www.tfdwme.live/post/c65ced15.html#comments">参与评论

]]>
golangq行~程模型范型举例 http://www.tfdwme.live/post/8db3abae.html http://www.tfdwme.live/post/8db3abae.html#comments http://www.tfdwme.live/post/8db3abae.html

在实际的日常开发中Q按照场景来考虑golang的ƈ行编E模型是比较合适的一U做法, q样既避免了IQ又能清晰易懂,代入感比较强

  • 场景一 q行处理很多dQQ务之间彼此不用进行信息汇L者通信

比如现在我们有一个程序,是要h很多URLQ只要每个协E能发出h便可Q没必要验证hl果和请求进行时讄数据Q或者通信数据Q?q种场景因ؓ没有涉及到数据流的走向,所以用WaitGroup比较合?/p>


var wg sync.WaitGroup

func ReqUrl() {
  // hURL

  defer wg.Done()
}

func main() {
  urlCout := 10
  for i := 0; i < urlCout; i++ {
    wg.Add(1)
    go ReqUrl()
  }

  wg.Wait()
}


  • 场景?q行处理很多dQQ务之间彼此需要进行信息汇L者通信 q是上面的场景,但是现在我们需要统计url的请求结果,假如有一个urlhp|Q则E序退?/li>

var FailUrl chan int

func ReqUrl()  {
  // hURL
  res := 1      // hl果不成?  if res == 1 {
    FailUrl <- 1
  }
}

func main() {
  urlCount := 10
  for i := 0; i < urlCount; i++ {
    go ReqUrl()
  }

  // 监听 FailUrlQ?只要有一个urlp|Q则退?  for {
    select {
    case fail := <- FailUrl:
      fmt.Println(fail)
      os.Exit(fail)
    }
  }
}


其他的场景后l再补充

本文链接Q?a href="http://www.tfdwme.live/post/8db3abae.html">http://www.tfdwme.live/post/8db3abae.htmlQ?a href="http://www.tfdwme.live/post/8db3abae.html#comments">参与评论

]]>
Concurrency in Go MW记一 http://www.tfdwme.live/post/0fb4132e.html http://www.tfdwme.live/post/0fb4132e.html#comments http://www.tfdwme.live/post/0fb4132e.html
  • Mutex ?RWMutex 的区?/li>

Mutex会锁住声明语句之内的所有的内存Q上下文QIO{,是完全资源独享的 RWMutex只会所以声明语句之内的内存d的资源,其他的资源是不会独n锁住?所以假如只是内存读写的需求,用RWMutex的效率远比Mutex要高

本文链接Q?a href="http://www.tfdwme.live/post/0fb4132e.html">http://www.tfdwme.live/post/0fb4132e.htmlQ?a href="http://www.tfdwme.live/post/0fb4132e.html#comments">参与评论

]]>
关于golang范型函数的ȝ1 http://www.tfdwme.live/post/95d3a3ba.html http://www.tfdwme.live/post/95d3a3ba.html#comments http://www.tfdwme.live/post/95d3a3ba.html

Z么是 关于golang范型函数的ȝ1Q?因ؓ自己也不定以后会有什么ȝQ所以先?Q哈哈~

一D늨序看?golang 的范型函数的关键问题Q以前一直被数据cd误导了, 要ȝ的都在代码里了,直接上代码了?/p>


package main

/**
关于范型函数的两个要ҎȝQ以前一直以?范型函数要匹配好传入的参数数据类型,
然后要定义好q回的数据类型,其实不是q样的, 因ؓ传入的参??q回的参数都
是在 调用 范型E序 的代码块d理的Q范型函数根本不用考虑

1.  传入的参数在 调用?interface ?2.  q回的数据必L  interface 化,然后在调用处获得之后Q自己根本已l有的数据类型去做适配
 */

import (
  "fmt"
)

type UserT interface {
  GetUser()
}

type User struct {
  Id    int
  Name  string
}

func (u User)GetUser() User {
  return u
}

func PattAll(m map[interface{}]interface{}) interface{} {
  // 范型函数的另外一个要点就?输出的类型是  interface{}Q?然后输出的数据就留给调用q个范型函数的逻辑代码d理就?  // 因ؓ调用q个函数的逻辑代码的代码块是有 原来 m 的所有适配的数据类型的Q?范型函数Ҏ不用q个数据cd有无的问?  fmt.Println(m)
  return m
}


// 上面的逻辑可以理解为是?User l构?type ?
func main() {
  u := User{Id: 99, Name: "okok"}

  // 范型函数的注意力逻辑Q应该是在把要传入的参数对象  interfaces 化,适配所有的传入参数cd可以了
  m := make(map[interface{}]interface{})

  var s string
  s = "hello"
  m[0] = s

  m[1] = u

  //fmt.Println(m)
  PattAll(m)
}



本文链接Q?a href="http://www.tfdwme.live/post/95d3a3ba.html">http://www.tfdwme.live/post/95d3a3ba.htmlQ?a href="http://www.tfdwme.live/post/95d3a3ba.html#comments">参与评论

]]>
关于eiblog的二ơ修ҎE记?/title> <link>http://www.tfdwme.live/post/def1bd58.html</link> <comments>http://www.tfdwme.live/post/def1bd58.html#comments</comments> <guid>http://www.tfdwme.live/post/def1bd58.html</guid> <description> <![CDATA[<blockquote> <p>q行时加载博客程序运行的时候,初始化dbq接Ӟ已l把一些需要用到的数据从数据库取出来,以后都不要再ơ查询,所以博客的性能q是不错的, 该逻辑代码?/p> <pre><code class="language-go"> func init() { 数据库加索引 err := mgo.Index(DB, COLLECTION_ACCOUNT, []string{"username"}) if err != nil { logd.Fatal(err) } err = mgo.Index(DB, COLLECTION_ARTICLE, []string{"id"}) if err != nil { logd.Fatal(err) } err = mgo.Index(DB, COLLECTION_ARTICLE, []string{"slug"}) if err != nil { logd.Fatal(err) } // d帐号信息 loadAccount() // 获取文章数据 loadArticles() // 生成markdown文档 // 在这里初始化拿文章的数据内容Q?初始函数出当前|的文章,做了分页处理 go generateMarkdown() // 启动定时? go timer() // 获取评论数量 go PostsCount() } </code></pre> <p>装蝲文章信息Q例如标题,内容Q标{Q逻辑代码?/p> <pre><code class="language-go"> func loadArticles() { err := mgo.FindAll(DB, COLLECTION_ARTICLE, mgo.M{"isdraft": false, "deletetime": mgo.M{"$eq": time.Time{}}}, &Ei.Articles) if err != nil { logd.Fatal(err) } sort.Sort(Ei.Articles) for i, v := range Ei.Articles { // 渲染文章 GenerateExcerptAndRender(v) Ei.MapArticles[v.Slug] = v // 分析文章 if v.ID < setting.Conf.General.StartID { continue } if i > 0 { v.Prev = Ei.Articles[i-1] } if Ei.Articles[i+1].ID >= setting.Conf.General.StartID { v.Next = Ei.Articles[i+1] } upArticle(v, false) } Ei.CH <- SERIES_MD Ei.CH <- ARCHIVE_MD } </code></pre> <p>把一些需要的文章信息从数据库取出?/p> <pre><code class="language-go"> err := mgo.FindAll(DB, COLLECTION_ARTICLE, mgo.M{"isdraft": false, "deletetime": mgo.M{"$eq": time.Time{}}}, &Ei.Articles) </code></pre> <p>上面是把数据库需要的一些数据进行初始装载, 至于对系l用的 Ei 变量的一些信息, 是在这个函数进行初始化?/p> <pre><code class="language-go"> func upArticle(artc *Article, needSort bool) { // tag for _, tag := range artc.Tags { Ei.Tags[tag] = append(Ei.Tags[tag], artc) if needSort { sort.Sort(Ei.Tags[tag]) } } // serie for i, serie := range Ei.Series { if serie.ID == artc.SerieID { Ei.Series[i].Articles = append(Ei.Series[i].Articles, artc) if needSort { sort.Sort(Ei.Series[i].Articles) Ei.CH <- SERIES_MD } break } } // archive y, m, _ := artc.CreateTime.Date() for i, archive := range Ei.Archives { if ay, am, _ := archive.Time.Date(); y == ay && m == am { Ei.Archives[i].Articles = append(Ei.Archives[i].Articles, artc) if needSort { sort.Sort(Ei.Archives[i].Articles) Ei.CH <- ARCHIVE_MD } return } } Ei.Archives = append(Ei.Archives, &Archive{Time: artc.CreateTime, Articles: SortArticles{artc}}) if needSort { Ei.CH <- ARCHIVE_MD } } </code></pre> <p>上面q个函数的调用发生在</p> <pre><code class="language-go"> // 在函?loadArticles ?upArticle(newArtc, true) </code></pre> <p>本文链接Q?a href="http://www.tfdwme.live/post/def1bd58.html">http://www.tfdwme.live/post/def1bd58.html</a>Q?a href="http://www.tfdwme.live/post/def1bd58.html#comments">参与评论 </a></p>]]> </description> </item> <item> <title>python gevent实践应用范例 http://www.tfdwme.live/post/24c8af01.html http://www.tfdwme.live/post/24c8af01.html#comments http://www.tfdwme.live/post/24c8af01.html

python gevent实践

gevent主要是用来实现python的ƈ发处理的Qƈ发的核心思想是将较大的Q务分解ؓ一l子dQ这些子d被安排ؓ同时或异步运行,而不是一ơ一个或同步q行?两个子Q务之间的切换UCؓ上下文切换?/p>

gevent中的上下文切换是通过yielding完成的。下面通过一些代码来直观感受gevent的用法?/p>

  • 两个通过调用gevent.sleepQ?怺产生的两个上下文Q?gevent会自动帮我们切换上下文处?/li>

import gevent 

def foo():
  print("Running in foo")
  gevent.sleep(0)
  print("再次显性地切换上下文到foo")

def bar():
  print("显性地切换上下文到bar")
  gevent.sleep(0)
  print("E序暗地自动切换回上下文到bar")

gevent.joinall([
  gevent.spawn(foo),
  gevent.spawn(bar),
])



  • 几个处理逻辑q行处理的例?/li>

import gevent 
import time 
from gevent import select 

start = time.time()
tic = lambda:  'at %1.1f seconds' % (time.time() - start)


def gr1():
  # E序在这里处理需要点旉Q?但是我们q不希望E序停在q里
  print("gr1 开始轮? %s" % tic())
  select.select([], [], [], 2)
  print('gr1 l束轮询: %s' % tic())

def gr2():
  # E序在这里处理需要点旉Q?但是我们q不希望E序停在q里
  print('gr2 开始轮? %s' % tic())
  select.select([], [], [], 2)
  print('gr2 l束轮询: %s' % tic())

def gr3():
  print('轮询需?U,q个时候gr3 可以做一些其他的逻辑处理Q?当程序在轮询的时? {你妹啊, %s' % tic())
  gevent.sleep(1)


gevent.joinall([
  gevent.spawn(gr1),
  gevent.spawn(gr2),
  gevent.spawn(gr3),
])



  • 同步处理和异步处理的区别

import gevent
import random

def task(pid):
  """
  处理l果不确定的d
  """
  gevent.sleep(random.randint(0, 2) * 0.001)
  print("d %s done" % pid)


def syncDo():
  for i in range(1, 10):
    task(i)

def asyncDo():
  threads = [gevent.spawn(task, i) for i in range(10)] 
  gevent.joinall(threads)

print("同步处理...")
syncDo()

print("异步处理...")
asyncDo()



  • q行h|络资源

import gevent.monkey
gevent.monkey.patch_socket()

import gevent
import urllib.request
import simplejson as json

def fetch(pid):
    response = urllib.request.urlopen('http://quan.suning.com/getSysTime.do')
    result = response.read()
    json_result = json.loads(result)
    datetime = json_result['sysTime2']

    print('Process %s: %s' % (pid, datetime))
    return json_result['sysTime2']

def synchronous():
    for i in range(1,10):
        fetch(i)

def asynchronous():
    threads = []
    for i in range(1,10):
        threads.append(gevent.spawn(fetch, i))
    gevent.joinall(threads)

print('Synchronous:')
synchronous()

print('Asynchronous:')
asynchronous()




  • 异步通信辑ֈU程{待的目?/li>

import gevent
from gevent.event import Event 


evt = Event()

def setter():
  print("A: L待我Q我正在做一些事?..")
  gevent.sleep(3)
  print("OK, 我已l完成了")
  evt.set()

def waiter():
  print("我在{待?quot;)
  evt.wait()
  print("已经{待完成。。?quot;)

def main():
  gevent.joinall([
    gevent.spawn(setter),
    gevent.spawn(waiter),
    gevent.spawn(waiter),
    gevent.spawn(waiter),
    gevent.spawn(waiter),
    gevent.spawn(waiter),
  ])


if __name__ == "__main__": main()



  • 利用队列L完成job/woker代码逻辑模型

import gevent
from gevent.queue import Queue, Empty

tasks = Queue(maxsize = 3)

def worker(name):
  try:
    while True:
      task = tasks.get(timeout = 1)    # 
      print("worker %s 正在处理d %s" % (name, task))
      gevent.sleep(0)
  except Empty:
    print("队列处理完成Q?退?quot;)


def boss():
  for i in range(1, 10):
    tasks.put(i)
  print("已经分配完所有Q务给 worker1, work1会P代处?..")

  for i in range(10, 20):
    tasks.put(i)  
  print("已经分配完所有Q务给 worker2, work1会P代处?..")

gevent.joinall([
  gevent.spawn(boss),
  gevent.spawn(worker, "steven"),
  gevent.spawn(worker, "john"),
  gevent.spawn(worker, "bob"),
])


  • Erlang的ACTOR处理模型, 模拟发射??接收器ƈ行处?/li>

# actor
import gevent
from gevent.queue import Queue 

class Actor(gevent.Greenlet):

  def __init__(self):
    self.inbox = Queue()
    Greenlet.__init__(self)

  def recv(self, msg):
    raise NotImplemented()

  def _run(self):
    self.running = True

    while self.running:
      msg = self.inbox.get()
      self.recv(msg)



# ping & pong
import gevent
from gevent.queue import Queue 
from gevent import Greenlet 

class Pinger(Actor):
  def recv(self, msg):
    print(msg)
    pong.inbox.put("ping")
    gevent.sleep(0)

class Ponger(Actor):
  def recv(self, msg):
    print(msg)
    ping.inbox.put("pong")
    gevent.sleep(0)

ping = Pinger()
pong = Ponger()

ping.start()
pong.start()

ping.inbox.put("start")
gevent.joinall([ping, pong])



其他应用要在实践中用体会?/p>

本文链接Q?a href="http://www.tfdwme.live/post/24c8af01.html">http://www.tfdwme.live/post/24c8af01.htmlQ?a href="http://www.tfdwme.live/post/24c8af01.html#comments">参与评论

]]>
Cơ优化python循环代码逻辑的过E?/title> <link>http://www.tfdwme.live/post/8ca55381.html</link> <comments>http://www.tfdwme.live/post/8ca55381.html#comments</comments> <guid>http://www.tfdwme.live/post/8ca55381.html</guid> <description> <![CDATA[<blockquote> <h3 id="toc_0">问题描述:</h3> <p>一个含?0W元素的列表A,列表的元素都是字W串,现在要@?0Wơ,每次都要判断一下B字符串是否存在这个A列表里面Q有什么优化策略吗Q?/p> <h3 id="toc_1">问题现状Q?/h3> <p>如果用普通的逻辑来写Q?E序会类g面:</p> <pre><code class="language-python"> tl = [] for i in range(300000): tl.append(i) for j in range(100000): if k in tl: print "hit" </code></pre> <p>如果像上面的写法Q?E序性能会随着 10W q个for循环的增长而几何下降?/p> <h3 id="toc_2">正确的姿?/h3> <p>因ؓpython的list本n是属于不q箋的内存, 所以in不停止蟩跃各个元素的指针Q造成性能的下降?/p> <ul> <li>优化方式1: list转成dict的keyQ?然后用dict的in来检查匹配, q个方式是因为用ind断dict的keys是否存在Q首先dict底层的储存是采用hash储存QinLdict的键Q本来寻扄对象也是一个生成器Q综合这两个因素Q所以用q种方式性能会大大提升?/li> </ul> <pre><code class="language-python"> td = dict() for i in range(300000): td.setdefault(i, None) for j in range(100000): if k in td: print "hit" </code></pre> <ul> <li>优化方式2: 用numpy的array数据cdQ但q个前提是每个元素的数据cd都要一P不然array会报错。因为array本n是一块连l的大内存,所以@环匹配的时候, 不用跌内存LQ这样也能大大提高性能?/li> </ul> <pre><code class="language-python"> import numpy as np tl = [] for i in range(300000): tl.append(i) tla = np.array(tl) for j in range(100000): if k in tla: print "hit" </code></pre> <p>至于上面两种方式的性能ҎQ有兴趣p己动手试下吧 :)</p> <p>?/p> <p>本文链接Q?a href="http://www.tfdwme.live/post/8ca55381.html">http://www.tfdwme.live/post/8ca55381.html</a>Q?a href="http://www.tfdwme.live/post/8ca55381.html#comments">参与评论 </a></p>]]> </description> </item> <item> <title>一张图Q一D代码解释RPC是怎么回事 http://www.tfdwme.live/post/811b6130.html http://www.tfdwme.live/post/811b6130.html#comments http://www.tfdwme.live/post/811b6130.html

RPC的代码逻辑程

服务?/h4>
  • 服务端定义好RPC可以调用的函数A
  • 服务端注册函数AQ作用ؓ声明客户端可调用Q?/li>
  • 服务端完成可Ҏ 字符?“A?来调?函数A 的逻辑代码(反射机制Q?/li>
  • 服务端有函数A正常执行所需的数据参?A(xx, yy), 假如 xx是一个listQ?yy是一个mapQ?有参数类型即?/li>
  • q行|络服务Q监听端口,接收h ———–

客户?/h3>
  • 客户端定义好 函数A需要的参数 xx(list)Q?yy(map)
  • 客户端发Ll请求, 传输函数A的字W串声明Q?加密传输参数xx, yyQ类型要跟服务端保持一_一׃个对?/li>
  • {待服务端的执行q回Q实际上函数执行是在服务端进?/li>

本文链接Q?a href="http://www.tfdwme.live/post/811b6130.html">http://www.tfdwme.live/post/811b6130.htmlQ?a href="http://www.tfdwme.live/post/811b6130.html#comments">参与评论

]]> npx 是什?/title> <link>http://www.tfdwme.live/post/8dae5eaf.html</link> <comments>http://www.tfdwme.live/post/8dae5eaf.html#comments</comments> <guid>http://www.tfdwme.live/post/8dae5eaf.html</guid> <description> <![CDATA[<blockquote> <p>最q我在更?npm 5.2.0 的时候发CC送一Q自动安装了 npx?/p> <p>一个月?npx 是前端必会的知识,怿?; )</p> <p>npx 是什?/p> <p>Ҏ zkat/npx 的描qͼnpx 会帮你执行依赖包里的二进制文件?/p> <p>举例来说Q之前我们可能会写这L命oQ?/p> <p>npm i -D webpack</p> <p>./node_modules/.bin/webpack -v</p> <p>如果你对 bash 比较熟,可能会写成这?/p> <p>npm i -D webpack</p> <p><code>npm bin</code>/webpack -v</p> <p>有了 npxQ你只需要这?/p> <p>npm i -D webpack</p> <p>npx webpack -v</p> <p>也就是说 npx 会自动查扑ֽ前依赖包中的可执行文Ӟ如果找不刎ͼ׃?PATH 里找。如果依然找不到Q就会帮你安装!</p> <p>npx 甚至支持q行q程仓库的可执行文gQ如</p> <p>$ npx github:piuccio/cowsay hello</p> <p>npx: 1 安装成功Q用?1.663 U?/p> <p>再比?npx http-server 可以一句话帮你开启一个静态服务器Q(W一ơ运行会E微慢一些)</p> <p>$ npx http-server</p> <p>npx: 23 安装成功Q用?48.633 U?/p> <p>Starting up http-server, serving ./</p> <p>Available on:</p> <p><a href="http://127.0.0.1:8080" rel="nofollow">http://127.0.0.1:8080</a></p> <p><a href="http://192.168.5.14:8080" rel="nofollow">http://192.168.5.14:8080</a></p> <p>Hit CTRL-C to stop the server</p> <p>本文链接Q?a href="http://www.tfdwme.live/post/8dae5eaf.html">http://www.tfdwme.live/post/8dae5eaf.html</a>Q?a href="http://www.tfdwme.live/post/8dae5eaf.html#comments">参与评论 </a></p>]]> </description> </item> <item> <title>与碎片交战:《深度工作》摘?/title> <link>http://www.tfdwme.live/post/8798cc12.html</link> <comments>http://www.tfdwme.live/post/8798cc12.html#comments</comments> <guid>http://www.tfdwme.live/post/8798cc12.html</guid> <description> <![CDATA[<blockquote> <p>与碎片交战:《深度工作》摘?- 二向?<a href="https://blog.dingkewz.com/post/books/deep_work/" rel="nofollow">https://blog.dingkewz.com/post/books/deep_work/</a></p> <p>单的_看手机Q多看书?/p> <p>片段一:</p> <p>我等采石之h当心怀大教堂之愿景?…?在一个项目的整体l构之内QLI间展示个性和匠心……百q之后,我们的技艺或许如今日的土建工E看待中世纪大教堂徏造者用的技法一样陈旧,但是我们的匠心却会得到尊重?/p> <p>片段? 极乐?/p> <p>极乐机(Eudaimonia MachineQ,是一座徏{,其目的在于,创造一U环境,让用这w处其中时可以达到深度h体繁荣状态,卛_C力极限的成果?/p> <p>整个建筑l构是一座一层高的长方ŞQ有5个房间组成,几个戉K没有互相q通的走廊Q必ȝq一间房间才能进入到下一间?/p> <p>W一间是陈列室,用于展示在这座徏{中产出的深度工作案例?/p> <p>W二间是沙龙Q旨在酝酿出一U“徘徊于强烈的好奇和争辩之间“的情AQ从整体上把控你在q建筑中想要深入探I的一些想法?/p> <p>W三间是图书馆,怹储存了这台机器所产出的所有工作,同时q存有此前工作中使用q的图书和其他资源?/p> <p>W四间是办公I间Q有会议室,白板和一些带桌子的小隔间Q用于完成“Q工作?/p> <p>最后一间是“深度工作室”,有非常良好的隔音效果Q用于实现全w心投入和毫无干扰工作?/p> <p>我的博客是我的极乐?/p> <p>片段?</p> <p>如果在你全部的清醒时间里Q都能给自己的大脑找到有意义的事情去做,而不是放任自己在qL的状态下漫无目的地浏览几个小时网,那么在一天结束时Q你会觉得更加充实,W二天开始时更加L?/p> <p>本文链接Q?a href="http://www.tfdwme.live/post/8798cc12.html">http://www.tfdwme.live/post/8798cc12.html</a>Q?a href="http://www.tfdwme.live/post/8798cc12.html#comments">参与评论 </a></p>]]> </description> </item> <item> <title>BSON与JSON的区?/title> <link>http://www.tfdwme.live/post/ec155526.html</link> <comments>http://www.tfdwme.live/post/ec155526.html#comments</comments> <guid>http://www.tfdwme.live/post/ec155526.html</guid> <description> <![CDATA[<blockquote> <p>BSON是由10gen开发的一个数据格式,目前主要用于MongoDB中,是MongoDB的数据存储格式。BSONZJSON格式Q选择JSONq行攚w的原因主要是JSON的通用性及JSON的schemaless的特性?/p> <p>BSON主要会实C下三点目标:</p> <p>1.更快的遍历速度 对JSON格式来说Q太大的JSONl构会导致数据遍历非常慢。在JSON中,要蟩q一个文档进行数据读取,需要对此文档进行扫描才行,需要进行麻烦的数据l构匚wQ比如括L匚wQ而BSON对JSON的一大改q就是,它会JSON的每一个元素的长度存在元素的头部,q样你只需要读取到元素长度p直接seek到指定的点上q行d了?/p> <p>2.操作更简?对JSON来说Q数据存储是无类型的Q比如你要修改基本一个|??0Q由于从一个字W变成了两个Q所以可能其后面的所有内定w需要往后移一位才可以。而用BSONQ你可以指定q个列ؓ数字列,那么无论数字?长到10q是100Q我们都只是在存储数字的那一位上q行修改Q不会导致数据总长变大。当Ӟ在MongoDB中,如果数字从整形增大到长整型,q是会导致数据总长变大的?/p> <p>3.增加了额外的数据cd JSON是一个很方便的数据交换格式,但是其类型比较有限。BSON在其基础上增加了“byte array”数据类型。这使得二进制的存储不再需要先base64转换后再存成JSON。大大减了计算开销和数据大?/p> <p>当然Q在有的时候,BSON相对JSON来说也ƈ没有I间上的优势Q比如对{“field?7}Q在JSON的存储上7只用了一个字节,而如果用BSONQ那是臛_4个字节(32位)</p> <p>目前?0gen的努力下QBSON已经有了针对多种语言的编码解码包。ƈ且都是Apache 2 license下开源的。ƈ且还在随着MongoDBq一步地发展。关于BSON</p> <p>本文链接Q?a href="http://www.tfdwme.live/post/ec155526.html">http://www.tfdwme.live/post/ec155526.html</a>Q?a href="http://www.tfdwme.live/post/ec155526.html#comments">参与评论 </a></p>]]> </description> </item> <item> <title>理解 Go Context 机制 http://www.tfdwme.live/post/015921d0.html http://www.tfdwme.live/post/015921d0.html#comments http://www.tfdwme.live/post/015921d0.html

原文地址 http://lanlingzi.cn/post/technical/2016/0802_go_context/

1 什么是 Context

最q在公司分析 gRPC 源码Qproto 文g生成的代码,接口函数W一个参数统一?code>ctx context.Context接口Q公怸同事都不了解这栯计的出发Ҏ什么,其实我也不了解其背后的原理。今天趁着妮妲台风妹子正面登陆深圳Q全市停工、停课、停业,在家休息找了一些资料研I把玩一把?/p>

Context通常被译?code>上下?/code>Q它是一个比较抽象的概念。在公司技术讨论时也经怼提到上下?/code>。一般理解ؓE序单元的一个运行状态、现场、快照,而翻译中上下又很好地诠释了其本质Q上下上下则是存在上下层的传递,?/code>会把内容传递给?/code>。在 Go 语言中,E序单元也就指的?Goroutine?/p>

每个 Goroutine 在执行之前,都要先知道程序当前的执行状态,通常这些执行状态封装在一?code>Context变量中,传递给要执行的 Goroutine 中。上下文则几乎已l成Z递与h同生存周期变量的标准Ҏ。在|络~程下,当接收到一个网l请?RequestQ处?Request Ӟ我们可能需要开启不同的 Goroutine 来获取数据与逻辑处理Q即一个请?RequestQ会在多?Goroutine 中处理。而这?Goroutine 可能需要共?Request 的一些信息;同时?Request 被取消或者超时的时候,所有从q个 Request 创徏的所?Goroutine 也应该被l束?/p>

2 context ?/h2>

Go 的设计者早考虑多个 Goroutine ׃n数据Q以及多 Goroutine 理机制?code>Context介绍请参?Go Concurrency Patterns: ContextQ?a href="http://godoc.org/golang.org/x/net/context" rel="nofollow">golang.org/x/net/context 包就是这U机制的实现?/p>

context包不仅实C在程序单元之间共享状态变量的ҎQ同时能通过单的ҎQ我们在被调用E序单元的外部,通过讄 ctx 变量|过期或撤销q些信号传递给被调用的E序单元。在|络~程中,若存?A 调用 B ?API, B 再调?C ?APIQ若 A 调用 B 取消Q那也要取消 B 调用 CQ通过?A,B,C ?API 调用之间传?code>ContextQ以及判断其状态,p解决此问题,q是Z?gRPC 的接口中带上ctx context.Context参数的原因之一?/p>

Go1.7(当前?RC2 版本) 已将原来?code>golang.org/x/net/context包挪入了标准库中Q放?$GOROOT/src/context 下面。标准库?code>net?code>net/http?code>os/exec都用Ccontext。同时ؓ了考虑兼容Q在?code>golang.org/x/net/context包下存在两个文gQ?code>go17.go是调用标准库?code>context包,?code>pre_go17.go则是之前的默认实玎ͼ其介l请参?go E序包源码解?/a>?/p>

context包的核心是Context接口Q其定义如下Q?/p>

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}
  • Deadline会返回一个超时时_Goroutine 获得了超时时间后Q例如可以对某些 io 操作讑֮时旉?/p>

  • DoneҎq回一个信道(channelQ,?code>Context被撤销或过期时Q该信道是关闭的Q即它是一个表C?Context 是否已关闭的信号?/p>

  • ?code>Done信道关闭后,ErrҎ表明Context 被撤的原因?/p>

  • Value可以?Goroutine ׃n一些数据,当然获得数据是协E安全的。但使用q些数据的时候要注意同步Q比如返回了一?mapQ而这?map 的读写则要加锁?/p>

Context接口没有提供Ҏ来设|其值和q期旉Q也没有提供Ҏ直接其自n撤销。也是_Context不能改变和撤销其自w。那么该怎么通过Context传递改变后的状态呢Q?/p>

3 context 使用

无论?GoroutineQ他们的创徏和调用关pLL像层层调用进行的Q就像h的辈分一P而更靠顶部的 Goroutine 应有办法d关闭其下属的 Goroutine 的执行(不然E序可能失控了Q。ؓ了实现这U关p,Context l构也应该像一|Q叶子节炚wL由根节点衍生出来的?/p>

要创?Context 树,W一步就是要得到根节点,context.Background函数的返回值就是根节点Q?/p>

func Background() Context

该函数返回空?ContextQ该 Context 一般由接收h的第一?Goroutine 创徏Q是与进入请求对应的 Context 根节点,它不能被取消、没有倹{也没有q期旉。它常常作ؓ处理 Request 的顶?context 存在?/p>

有了根节点,又该怎么创徏其它的子节点Q孙节点呢?context 包ؓ我们提供了多个函数来创徏他们Q?/p>

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key interface{}, val interface{}) Context

函数都接收一?code>Contextcd的参?code>parentQƈq回一?code>Contextcd的|q样层层创建出不同的节炏V子节点是从复制父节点得到的Qƈ且根据接收参数设定子节点的一些状态|接着可以将子节点传递给下层?Goroutine 了?/p>

再回C前的问题Q该怎么通过Context传递改变后的状态呢Q?code>Context?Goroutine 无法取消某个操作Q其实这也是W合常理的,因ؓq些 Goroutine 是被某个?Goroutine 创徏的,而理应只有父 Goroutine 可以取消操作。在?Goroutine 中可以通过 WithCancel Ҏ获得一?cancel ҎQ从而获?cancel 的权利?/p>

W一?code>WithCancel函数Q它是将父节点复制到子节点,q且q返回一个额外的CancelFunc函数cd变量Q该函数cd的定义ؓQ?/p>

type CancelFunc func()

调用CancelFunc对象撤销对应?code>Context对象Q这是d撤销Context的方法。在父节点的Context所对应的环境中Q通过WithCancel函数不仅可创建子节点?code>ContextQ同时也获得了该节点Context的控制权Q一旦执行该函数Q则该节?code>Contextq束了Q则子节炚w要类似如下代码来判断是否已结束,q GoroutineQ?/p>

select {
    case <-cxt.Done():
        // do some clean...
}

WithDeadline函数的作用也差不多,它返回的 Context cd值同hparent的副本,但其q期旉?code>deadline?code>parent的过期时间共同决定。当parent的过期时间早于传入的deadline旉Ӟq回的过期时间应?code>parent相同。父节点q期Ӟ其所有的子孙节点必须同时关闭Q反之,q回的父节点的过期时间则?code>deadline?/p>

WithTimeout函数?code>WithDeadlinecMQ只不过它传入的是从现在开?Context 剩余的生命时ѝ他们都同样也都q回了所创徏的子 Context 的控制权Q一?code>CancelFunccd的函数变量?/p>

当顶层的 Request h函数l束后,我们可?cancel 掉某?contextQ从而层?Goroutine Ҏ判断cxt.Done()来结束?/p>

WithValue函数Q它q回parent的一个副本,调用该副本的 Value(key) Ҏ得?val。这h们不光将根节点原有的g留了Q还在子孙节点中加入了新的|注意若存?Key 相同Q则会被覆盖?/p>

3.1 结

context包通过构徏树型关系?ContextQ来辑ֈ上一?Goroutine 能对传递给下一?Goroutine 的控制。对于处理一?Request h操作Q需要采?code>context来层层控?GoroutineQ以及传递一些变量来׃n?/p>

  • Context 对象的生存周期一般仅Z个请求的处理周期。即针对一个请求创Z?Context 变量Q它?Context 树结构的根)Q在h处理l束后,撤销?ctx 变量Q释放资源?/p>

  • 每次创徏一?GoroutineQ要么将原有?Context 传递给 GoroutineQ要么创Z个子 Context q传递给 Goroutine?/p>

  • Context 能灵zd存储不同cd、不同数目的|q且使多?Goroutine 安全地读写其中的倹{?/p>

  • 当通过?Context 对象创徏?Context 对象Ӟ可同时获得子 Context 的一个撤销函数Q这L Context 对象的创建环境就获得了对?Context 要被传递到?Goroutine 的撤销权?/p>

  • 在子 Context 被传递到?goroutine 中,应该对该?Context ?Done 信道QchannelQ进行监控,一旦该信道被关闭(即上层运行环境撤销了本 goroutine 的执行)Q应dl止对当前请求信息的处理Q释放资源ƈq回?/p>

4 使用原则

Programs that use Contexts should follow these rules to keep interfaces consistent across packages and enable static analysis tools to check context propagation: 使用 Context 的程序包需要遵循如下的原则来满x口的一致性以及便于静态分析?/p>

  • Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. The Context should be the first parameter, typically named ctxQ不要把 Context 存在一个结构体当中Q显式地传入函数。Context 变量需要作为第一个参C用,一般命名ؓ ctxQ?/p>

  • Do not pass a nil Context, even if a function permits it. Pass context.TODO if you are unsure about which Context to useQ即使方法允许,也不要传入一?nil ?ContextQ如果你不确定你要用什?Context 的时候传一?context.TODOQ?/p>

  • Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functionsQ?context ?Value 相关Ҏ只应该用于在E序和接口中传递的和请求相关的元数据,不要用它来传递一些可选的参数Q?/p>

  • The same Context may be passed to functions running in different goroutines; Contexts are safe for simultaneous use by multiple goroutinesQ同L Context 可以用来传递到不同?goroutine 中,Context 在多?goroutine 中是安全的;


参考: [1] https://blog.golang.org/context [2] http://blog.golang.org/pipelines [3] http://studygolang.com/articles/5131 [4] http://blog.csdn.net/sryan/article/details/51969129 [5] https://peter.bourgon.org/blog/2016/07/11/context.html [6] http://www.tuicool.com/articles/vaieAbQ

本文链接Q?a href="http://www.tfdwme.live/post/015921d0.html">http://www.tfdwme.live/post/015921d0.htmlQ?a href="http://www.tfdwme.live/post/015921d0.html#comments">参与评论

]]> 解释pykafka参数最详细的记?/title> <link>http://www.tfdwme.live/post/184913ab.html</link> <comments>http://www.tfdwme.live/post/184913ab.html#comments</comments> <guid>http://www.tfdwme.live/post/184913ab.html</guid> <description> <![CDATA[<blockquote> <ol> <li>Kafka</li> </ol> <p>  1. ?/p> <p>    Kafka 是一U分布式的、分区的、多副本的基于发布/订阅的消息系l。它是通过 zookeeper q行协调Q常见可以用?web/nginx 日志、访问日志、消息服务等。主要应用场景ؓQ日志收集系l和消息pȝ?/p> <p>    Kafka 的主要设计目标如下:</p> <p>      1. 以时间复杂度?O(1) 的方式提供持久化能力Q即使对 TB U别以上的数据也能保证常数时间的讉K性能?/p> <p>      2. 高吞吐率Q即使在十分廉h的机器上也能实现单机支持每秒 100K 条消息的传输?/p> <p>      3. 支持 Kafka Server (?Kafka 集群的服务器)间的消息分区Q及分布式消费,同时保证每个 partition 内的消息序传输?/p> <p>      4. 同时支持ȝ数据处理和实时数据处?/p> <p>  2. Kafka 架构</p> <p>囄描述</p> <p>    如上图所C,一?Kafka 集群pqproducer、若qconsumer、若qbrokerQ以及一个zookeeper集群所l成。Kafka通过zookeeper理集群配置Q选DleaderQ以及在consumer group发生变化时进行rebalance。producer使用push模式消息发布到brokerQconsumer使用pull模式从broker订阅q消Ҏ息?/p> <p>    Kafka名词解释Q?/p> <p>      brokerQ消息中间g处理l点Q一个Kafka节点是一个brokerQ多个broker可以l成一个Kafka集群Q相当于物理层面上的一台服务器?/p> <p>      topicQ存攑֐一cL息的位置Q是一个概念层面上的名词,Kafka集群可以负责多个topic的分发。(物理上不同topic的消息分开存储Q逻辑上一个topic的消息虽然保存于一个或多个broker上但用户只需指定消息的topic卛_生或消Ҏ据而不必关心数据存于何处)</p> <p>      partitionQtopic在物理层面上的分l,一个topic可以分ؓ多个partitionQ每个partition是一个有序的队列Q创建topic时可以指定partition数量Q每个partition对应于一个文件夹Q该文g夹下存储该partition的数据和索引文g。一般来说partition的数量大于等于broker的数量?/p> <p>      producerQ负责发布消息到Kafka broker</p> <p>      consumerQ消Ҏ息,每个consumer属于一个特定的consumer groupQ可为每个consumer指定group nameQ若不指定group name则ؓ默认的groupQ。用consumer high level APIӞ同一topic的一条消息只能被一个consumer group的一个consumer消费Q但多个consumer group可同时消费这条消息?/p> <p>      consumer groupQ每个consumer属于一个特定的consumer groupQconsumer group是实际记录的概念?/p> <p>  3. Kafka数据传输的事务特?/p> <p>    1. at most once</p> <p>      q种模式下consumer fetch消息Q先q行commitQ再q行处理。如果再处理消息的过E中出现异常Q下ơ重新开始工作就无法d之前已经认而未处理的消息?/p> <p>    2. at least once</p> <p>      消息臛_发送一ơ,如果消息未能接受成功Q可能会重发Q直到接收成功。消费者fetch消息Q然后处理消息,然后保存offset。如果消息处理成功之后,但是在保存offset阶段zookeeper异常D保存操作未能执行成功Q这导致接下来再次fetch时可能获得上ơ已l处理过的消息,q就是”at least once”,原因offset没有及时的提交给zookeeperQzookeeper恢复正常q是之前offset状态?/p> <p>    3. exactly once</p> <p>      消息只会发送一ơ,Kafka中ƈ没有严格的去实现Q我们认U策略在Kafka中是没有必要的?/p> <p>    通常情况下,Kafka默认保证at least once?/p> <p>  5. Push & Pull</p> <p>    作ؓ一个消息系l,Kafka遵@了传l的方式Q选择由producer向broker push消息Qƈ由consumer从broker中pull消息?/p> <p>    push模式很难适应消费速率不同的消费者,因ؓ消息发送速率是由broker军_的。push模式的目标就是以可能快的速度传递消息,但是q样很容易造成consumer来不及处理消息,典型的表现是拒绝服务以及|络拥塞。而pull模式可以Ҏconsumer的消费能力以适当的速率消费消息?/p> <p>  6. Topic & Partition</p> <p>    Topic在逻辑上可以认为是一个存在的queueQ每条消息都必须指定它的topicQ可以简单的理解为必L明把q条消息放进哪个queue里。ؓ了Kafka的吞吐率可以水^扩展Q物理上把topic分成一个或多个partitionQ每个partition在物理上对应一个文件夹Q该文g夹下存储q个partition的所有消息和索引文g?/p> <p>    每个日志文g都是”log entries”序列Q每一个log entry包含一?字节整型|gؓNQ,其后跟N个字节的消息体。每条消息都有一个当前partition下唯一?4字节的offsetQ它指明了这条消息的起始位置Q也是对数据的唯一标识QKafka中ƈ没有提供额外的烦引机制来存储offsetQ因为在Kafka中几乎不允许Ҏ息进?rdquo;随机d”。磁盘上log entry的存储格式如下:</p> <p>      message lengthQ? bytes(它的具体gؓ1+4+nQ如下所C)</p> <p>      ”magic” valueQ? byte</p> <p>      crcQ? bytes</p> <p>      payloadQn bytes</p> <p>    q个log entriesq׃个文件构成,而是分ؓ多个segmentQ每个segment名ؓ该segmentW一条消息的offset?rdquo;.kafka”l成。另外会有一个烦引文Ӟ它标明了每个segment下包含的log entry的offset范围?/p> <p>    因ؓ每条消息都被append到该partition中,是顺序写盘Q因此效率非帔RQ经验证Q顺序写盘比随机写内存q要高,q是Kafka高吞吐率的一个保证)?/p> <p>    每条消息被发送到topicӞ会根据指定的partition规则选择被存储到哪一个partition。如果partition规则设计的合理,所有的消息会均匀分配C同的partition里,q样实C水^扩展。(如果一个topic对应一个文Ӟ那这个文件所在的机器I/O会成ؓq个topic的性能瓉Q而partition解决了这个问题)。在创徏topicӞ可以?KAFKA_HOME/config/server.properties中指定这个partition的数?如下所C?Q当然也可以在topic创徏之后M改parition数量?/p> <h1 id="toc_0">The default number of log partitions per topic. More partitions allow greater</h1> <h1 id="toc_1">parallelism for consumption, but this will also result in more files across</h1> <h1 id="toc_2">the brokers.</h1> <p>num.partitions=3     在发送一条消息时Q可以指定这条消息的keyQproducerҎq个key和partition机制来判断这个将q条消息发送到哪个partition。paritition机制可以通过指定producer的paritition. classq一参数来指定,该class必须实现kafka.producer.Partitioner接口。(比如如果一个key能够被解析ؓ整数Q那么将对应的整CpartitionL取余Q可以作消息被发送到的partition id)</p> <p>  7. 历史数据删除机制</p> <p>    对于传统的message queue而言Q一般会删除已经消费q的消息Q而Kafka集群会保留所有的消息Q无论其被消费与否。当Ӟ׃盘限制Q不可能怹保留Q因此Kafka提供两种机制d除旧数据。一是基于时_一是基于partition文g大小。(例如可以通过配置$KAFKA_HOME/config/server.propertiesQ让Kafka删除一周前的数据,也可通过配置让Kafka在partition文g过1GB时删除旧数据Q?/p> <p>    q里要注意,因ؓKafkad特定消息的时间复杂度为O(1)Q即与文件大无养I所以这里删除文件与Kafka性能无关Q选择怎样的删除策略只与磁盘以及具体的需求有兟뀂另外,Kafka会ؓ每一个consumer group保留一些metadata信息—当前消费的消息的positionQ也即offset。这个offset由consumer控制。正常情况下consumer会在消费完一条消息后U性增加这个offset。当Ӟconsumer也可offset设成一个较的|重新消费一些消息。因为offet由consumer控制Q所以Kafka broker是无状态的Q它不需要标记哪些消息被哪些consumerq,不需要通过brokerM证同一个consumer group只有一个consumer能消Ҏ一条消息,因此也就不需要锁机制Q这也ؓKafka的高吞吐率提供了有力保障?/p> <p>  8. Consumer Group</p> <p>    对于E序员来_consumer group 是消?Kafka 消息队列中消息的接口Q每?consumer group 可以消费多个 topicQ对于每一?topic 可以有多个消费者实?consumerQ对应多个程序或者进E)。在消费q程中,同一?topic 中的消息只会被同一?consumer group 中的一?consumer 消费Q而不会出现重复订阅的情况。对于每一?consumer group 消费 topicQ可以手动commitQ也可以讄参数集群自动commit(认)消费q行的位|,保证下一ơ能接着从上ơ的位置l箋消费?/p> <p>    consumer group ?topic 一P也是直接使用p新徏的。如果直接新Z?consumerQ而不指定具体?consumer groupQ系l会自动的指定默认的 consumer groupQƈ且从最老的数据QEARLIESTQ位|开始消贏V?/p> <p>  详情参考:</p> <p>  <a href="http://developer.51cto.com/art/201501/464491.htm" rel="nofollow">http://developer.51cto.com/art/201501/464491.htm</a></p> <p>  <a href="http://geek.csdn.net/news/detail/229569" rel="nofollow">http://geek.csdn.net/news/detail/229569</a></p> <p>  <a href="http://www.cnblogs.com/likehua/p/3999538.html" rel="nofollow">http://www.cnblogs.com/likehua/p/3999538.html</a></p> <ol> <li>PyKafka 的?/li> </ol> <p>  1. 导入 pykafka 模块</p> <p>    import pykafka</p> <p>    from pykafka import KafkaClient</p> <p>  2. 初始?KafkaClient</p> <p>    client = KafkaClient(hosts=“127.0.0.1:9092,127.0.0.1:9093,…“) 可以通过 hosts 地址初始化,也可以?zookeeper_hosts q行初始化:</p> <p>    client = KafkaClient(zookeeper_hosts = ‘yq01-ps-4-m42-pc177.yq01:2181,yq01-ps-4-m42-pc186.yq01:2181,yq01-ps-4-m42-pc187.yq01:2181,yq01-ps-4-m42-pc191.yq01:2181,yq01-ps-4-m42-pc192.yq01:2181’)</p> <p>  3. Topic 对象</p> <p>    client.topics 可以查看当前所有的 topic?/p> <p>    topic = client.topics[‘bjhapp_history’]  #如果?topic 存在Q那么会选中对应?topicQ如果不存在Q会自动新徏?topic?/p> <p>    Topic 对象包含的方法:</p> <p>      1. get_balanced_consumer(consumer_group, managed=False, **kwargs) Q生成对?consumer_group ?topic 下消息消费的一?balanced_consumerQ与 simple_consumer 的差别在于如果有多个 consumer q来对同一?topic 的消息进行订阅,balanced_consumer 会自动^衡和分配 partitions l每?consumerQ而先q来?simple_consumer 会对当前 topic 的partition ?00%的占有权?/p> <p>        参数Qconsumer_groupQ消费的 consumer_group ?/p> <p>           managedQ是否对 consumer_group q行理</p> <p>           **kwargsQ对应于 consumer 对象的众多参?/p> <p>      2. get_producer(use_rdkafka=False, **kwargs)Q生成对?topic 的一个异步消?producer</p> <p>      3. get_simple_consumer(consumer_group=None, use_rdkafka=False, **kwargs)Q生成对?consumer_group ?topic 的一?simple_consumer</p> <p>      4. get_sync_producer(**kwargs)Q生成对 topic 的一个同?producer</p> <p>    成员变量Q?/p> <p>      nameQtopic 的名?/p> <p>      partitionsQ包含当?topic 对应 partitions 的字?/p> <p>  4. Producer 对象</p> <p>    1. 同步?producer 对象</p> <p>      producer = topic.get_sync_producer()</p> <p>      producer.produce(“test”)</p> <p>      同步?producer 对象发布消息Ӟ只有在确认消息成功发送到集群时才q回Q因此网l?IO 的速度会媄响程序的整体速度?/p> <p>    2. 异步?producer 对象</p> <p>      Z实现更高的吞吐量Q我们推荐用异步模式的 producerQ这?produce() 函数能够立即q回Qƈ且可以批量处理更多的消息Q而不用等待当前消息发布成功的认。我们通过队列的接口同样可以在之后收到消息发布成功的确认,需要设|参?delivery_reports = True?/p> <p>      producer = topic.get_producer(delivery_reports=True)  #初始化异步的 producer</p> <p>      count = 0  #定义 count 变量用来存储消息发送的条数Q以便于定期查之前的消息是否发送成?/p> <p>复制代码 def produce(msg, partition_key): global count producer.produce(msg, partition_key = partition_key) count += 1 if count % 10 == 0: while True: try: old_msg, exc = producer.get_delivery_report(block = False) if exc is not None: log.warn(“fail to delivery msg: %s, exc: %s, try again”, <br /> old_msg.partition_key, exc) if type(exc) is not MessageSizeTooLarge: producer.produce(old_msg.value, partition_key = old_msg.partition_key) else: log.info(“succ delivery msg: %s”, old_msg.partition_key) except Queue.Empty: break; 复制代码       上述代码每尝试发布十条消息,对之前发送的消息?delivery_report q行查,查看其发布是否成功的状态,通过 producer.get_delivery_report() 函数q回之前发送失败的消息和结果,如果没有发布成功Q会试重新q行发送。直?delivery_report 的队列ؓI?/p> <p>      要注?producer 发布消息时是先将消息存储在缓存区Q再缓存区的消息发布到 Kafka 集群。所以异步的 produce() 函数执行完后Q依焉要一定的旉来实现消息从~存区的发布。所以如果文件执行结束,producer 对象会自动释放,D消息发布不成功,q回错误QReferenceError: weakly-referenced object no longer exists。解x法,在程序的N让程序等待一D|间消息发布完成Q例如:sleep(6)</p> <p>  5. Consumer 对象</p> <p>    当一?PyKafka consumer 开始从一?topic 中订阅消息时Q它在记录器中的起始位置是由 auto_offset_reset ?reset_offset_on_start 两个参数定的?/p> <p>consumer = topic.get_simple_consumer( consumer_group = ‘my_group’, auto_offset_reset = OffsetType.EARLIEST, reset_offset_on_start=False )     同样Q是?Kafka 集群保有M之前?consumer group/topic/partition set 的消费偏U量也会影响数据的初始订阅点。一?new group/topic/partition set 是之前没有M commited offsetsQ一个存在的是?commited offsets 的。这两者的订阅点由下面的规则决定:</p> <p>      1. 对于一个新?consumer group/topic/partitionsQ不参?reset_offset_on_start 的参数是什么,都会?auto_offset_reset 指定的位|开始消息订阅?/p> <p>      2. 对于一个已l存在的 consumer group/topic/partitionsQ假讑֏?reset_offset_on_start 为falseQ那么消费会从上一ơ消费的偏移量之后开始进行(比如上一ơ的消费偏移量ؓ4Q那么消费会?开始)。假讑֏Cؓ trueQ会自动?auto_offset_reset 指定的位|开始消贏V?/p> <p>    TipsQ?/p> <p>    1. No handlers could be found for logger “pykafka.simpleconsumer”</p> <p>      错误的原因是 consumer 在订阅消息时需要有一?logger 来记录日志,如果有一个全局 logger 对象Q会自动的写入该全局对象中,否则会报q条信息Q但是不影响消息订阅?/p> <p>    2. 有的时候会出现 consumer 在订阅消息时q迟不能d现的情况Q这是由?KafkaClient 的未知原因导致的Q可以尝试在初始?consumer 的参C加上 consumer_timeout_ms 参数来解决问题。该参数表示 consumer 在返?None 前尝试等待可以消费的消息的时间?/p> <pre><code class="language-python"> import sys from pykafka import KafkaClient from pykafka.balancedconsumer import BalancedConsumer from pykafka.simpleconsumer import OwnedPartition, OffsetType reload(sys) sys.setdefaultencoding('utf8') #pykafka, need install PyKafka class PyKafka: consumer = None TOPIC = 'log_download' BROKER_LIST = '10.23.23.24:9092,10.23.23.21:9092' ZK_LIST = '10.23.23.24:2181,10.23.23.21:2181/sh-bt' server = topic = zsServer = None def __init__(self): print("begin pykafka") self.server = self.BROKER_LIST self.topic = self.TOPIC self.zkServer= self.ZK_LIST def getConnect(self): client = KafkaClient(hosts=self.server) topic = client.topics[self.topic] self.consumer = topic.get_balanced_consumer( consumer_group="zs_download_04", # 自己命o auto_offset_reset=OffsetType.LATEST,#在consumer_group存在的情况下Q设|此变量Q表CZ最新的开始取 #auto_offset_reset=OffsetType.EARLIEST, #reset_offset_on_start=True, #auto_commit_enable=True, zookeeper_connect=self.zkServer ) #self.consumer = topic.get_simple_consumer(reset_offset_on_start=False) self.consumer.consume() self.consumer.commit_offsets() return self.consumer def disConnect(self): #self.consumer.close() pass def beginConsumer(self): for oneLog in self.consumer: print(oneLog.offset) print(oneLog.value) if __name__ == '__main__': pk = PyKafka() pk.getConnect() pk.beginConsumer() </code></pre> <p>本文链接Q?a href="http://www.tfdwme.live/post/184913ab.html">http://www.tfdwme.live/post/184913ab.html</a>Q?a href="http://www.tfdwme.live/post/184913ab.html#comments">参与评论 </a></p>]]> </description> </item> <item> <title>golang的log包一般的使用范例 http://www.tfdwme.live/post/3da3d2f4.html http://www.tfdwme.live/post/3da3d2f4.html#comments http://www.tfdwme.live/post/3da3d2f4.html

package main

import (
  "log"
  "os"
  "io/ioutil"
  "fmt"
)

func main() {
  f, err := os.OpenFile("logfile.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  if err != nil {
    log.Fatalf("file open error : %v", err)
  }
  defer f.Close()
  //log.SetOutput(f)
  //log.Fatal("fatal test")    // Fatal 会直接造成E序退?  log.Println("print test")
  log.SetOutput(ioutil.Discard)    // 后面不会有log的输?  log.Println("This is a test log entry")    //  不会有输?  fmt.Println("last ....")     // q里l箋执行
}

本文链接Q?a href="http://www.tfdwme.live/post/3da3d2f4.html">http://www.tfdwme.live/post/3da3d2f4.htmlQ?a href="http://www.tfdwme.live/post/3da3d2f4.html#comments">参与评论

]]>
go语言intcd转化成stringcd的方?/title> <link>http://www.tfdwme.live/post/e2384cc5.html</link> <comments>http://www.tfdwme.live/post/e2384cc5.html#comments</comments> <guid>http://www.tfdwme.live/post/e2384cc5.html</guid> <description> <![CDATA[<blockquote> <p>go语言中intcd和stringcd都是属于基本数据cd</p> <p>两种cd的{化都非常?/p> <p>下面为大家提供两Uintcd转化成stringcd的方法!</p> <p>go语言的类型{化都在strconv package里面Q详情请参考:</p> <p><a href="http://golang.org/pkg/strconv" rel="nofollow">http://golang.org/pkg/strconv</a></p> <p>下面附上转化代码:</p> <p>package main</p> <p>import ( “fmt” “strconv” )</p> <p>var i int = 10</p> <p>func main() { // 通过ItoaҎ转换 str1 := strconv.Itoa(i)</p> <pre><code>// 通过SprintfҎ转换 str2 := fmt.Sprintf("%s", i) // 打印str1 fmt.Println(str1) // 打印str2 fmt.Println(str2) </code></pre> <p>}</p> <p>%d代表Integer</p> <h2 id="toc_0">详细说明请参?<a href="http://golang.org/pkg/fmt/" rel="nofollow">http://golang.org/pkg/fmt/</a></h2> <p>原文Q?a href="https://blog.csdn.net/love_se/article/details/7947511" rel="nofollow">https://blog.csdn.net/love_se/article/details/7947511</a></p> <p>本文链接Q?a href="http://www.tfdwme.live/post/e2384cc5.html">http://www.tfdwme.live/post/e2384cc5.html</a>Q?a href="http://www.tfdwme.live/post/e2384cc5.html#comments">参与评论 </a></p>]]> </description> </item> <item> <title>?Xmx1024m -Xms1024m -Xmn512m -Xss256k”——Javaq行参数(? http://www.tfdwme.live/post/422cd440.html http://www.tfdwme.live/post/422cd440.html#comments http://www.tfdwme.live/post/422cd440.html

JVM的堆的内存, 是通过下面面两个参数控制的

-Xms 最堆的大, 也就是当你的虚拟机启动后Q?׃分配q么大的堆内存给?-Xmx 是最大堆的大?/p>

当最堆占满后,会尝试进行GCQ如果GC之后q不能得到够的内存(GC未必会收集到所有当前可用内?Q分配新的对象,那么׃扩展堆,如果-Xmx讄的太,扩展堆就会失败,DOutOfMemoryError错误提示?/p>

实际上,l节不止于此Q?堆还会被分成几个不同的区域,分别应用不同的GC法


googleC一博文,贴出来,漫O看:http://unixboy.javaeye.com/blog/174173 JVM调优ȝ -Xms -Xmx -Xmn -Xss 堆大设|?JVM 中最大堆大小有三斚w限制Q相x作系l的数据模型Q?2-btq是64-bitQ限Ӟpȝ的可用虚拟内存限Ӟpȝ的可用物理内存限制?2位系l下Q一般限制在1.5G~2GQ?4为操作系l对内存无限制。我在Windows Server 2003 pȝQ?.5G物理内存QJDK5.0下测试,最大可讄?478m?典型讄Q?java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -Xmx3550mQ设|JVM最大可用内存ؓ3550M?-Xms3550mQ设|JVM促内存?550m。此值可以设|与-Xmx相同Q以避免每次垃圾回收完成后JVM重新分配内存?-Xmn2gQ设|年M大小?G。整个JVM内存大小=q轻代大?+ q老代大小 + 持久代大。持久代一般固定大ؓ64mQ所以增大年M后,会减小q老代大小。此值对pȝ性能影响较大QSun官方推荐配置为整个堆?/8?-Xss128kQ?讄每个U程的堆栈大。JDK5.0以后每个U程堆栈大小?MQ以前每个线E堆栈大ؓ256K。更具应用的U程所需内存大小q行调整。在相同物理?存下Q减这个D生成更多的线E。但是操作系l对一个进E内的线E数q是有限制的Q不能无限生成,l验值在3000~5000左右?java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0 -XX:NewRatio=4:讄q轻代(包括Eden和两个Survivor区)与年老代的比|除去持久代)。设|ؓ4Q则q轻代与q老代所占比gؓ1Q?Q年M占整个堆栈的1/5 -XX:SurvivorRatio=4Q设|年M中EdenZSurvivor区的大小比倹{设|ؓ4Q则两个SurvivorZ一个Eden区的比gؓ2:4Q一个Survivor区占整个q轻代的1/6 -XX:MaxPermSize=16m:讄持久代大ؓ16m?-XX:MaxTenuringThreshold=0Q设|垃圾最大年龄。如果设|ؓ0的话Q则q轻代对象不l过Survivor区,直接q入q老代。对于年老代比较多的应用Q可以提高效率。如果将此D|ؓ一个较大|则年M对象会在Survivor行多ơ复Ӟq样可以增加对象再年M的存zL_增加在年M卌回收的概论?回收器选择 JVMl了三种选择Q串行收集器、ƈ行收集器、ƈ发收集器Q但是串行收集器只适用于小数据量的情况Q所以这里的选择主要针对q行攉器和q发攉器。默认情况下QJDK5.0以前都是使用串行攉器,如果想用其他收集器需要在启动时加入相应参数。JDK5.0以后QJVM会根据当前系l配|进行判断?吞吐量优先的q行攉?如上文所qͼq行攉器主要以到达一定的吞吐量ؓ目标Q适用于科学技术和后台处理{?典型配置Q?java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelGCQ选择垃圾攉器ؓq行攉器。此配置仅对q轻代有效。即上述配置下,q轻代用ƈ发收集,而年老代仍旧使用串行攉?-XX:ParallelGCThreads=20Q配|ƈ行收集器的线E数Q即Q同时多个U程一赯行垃圑֛收。此值最好配|与处理器数目相{?java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:+UseParallelOldGCQ配|年老代垃圾攉方式为ƈ行收集。JDK6.0支持对年老代q行攉?java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:MaxGCPauseMillis=100:讄每次q轻代垃圑֛收的最长时_如果无法满此时_JVM会自动调整年M大小Q以满此倹{?java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy -XX:+UseAdaptiveSizePolicyQ设|此选项后,q行攉器会自动选择q轻代区大小和相应的Survivor区比例,以达到目标系l规定的最低相应时间或者收集频率等Q此值徏议用ƈ行收集器Ӟ一直打开?响应旉优先的ƈ发收集器 如上文所qͼq发攉器主要是保证pȝ的响应时_减少垃圾攉时的停顿旉。适用于应用服务器、电信领域等?典型配置Q?java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGCQ设|年老代为ƈ发收集。测试中配置q个以后Q?XX:NewRatio=4的配|失效了Q原因不明。所以,此时q轻代大最好用-Xmn讄?-XX:+UseParNewGC:讄q轻代ؓq行攉。可与CMS攉同时使用。JDK5.0以上QJVM会根据系l配|自行设|,所以无需再设|此倹{?java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompactionQ由于ƈ发收集器不对内存I间q行压羃、整理,所以运行一D|间以后会产生“碎片”,使得q行效率降低。此D|运行多次GC以后对内存空间进行压~、整理?-XX:+UseCMSCompactAtFullCollectionQ打开对年老代的压~。可能会影响性能Q但是可以消除碎?辅助信息 JVM提供了大量命令行参数Q打C息,供调试用。主要有以下一些: -XX:+PrintGC 输出形式Q[GC 118250K->113543K(130112K), 0.0094143 secs] [Full GC 121376K->10414K(130112K), 0.0650971 secs]

-XX:+PrintGCDetails 输出形式Q[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

-XX:+PrintGCTimeStamps -XX:+PrintGCQPrintGCTimeStamps可与上面两个混合使用 输出形式Q?1.851: [GC 98328K->93620K(130112K), 0.0082960 secs] -XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,E序未中断的执行旉。可与上面؜合?输出形式QApplication time: 0.5291524 seconds -XX:+PrintGCApplicationStoppedTimeQ打印垃圑֛收期间程序暂停的旉。可与上面؜合?输出形式QTotal time for which application threads were stopped: 0.0468229 seconds -XX:PrintHeapAtGC:打印GC前后的详l堆栈信?输出形式Q?34.702: [GC {Heap before gc invocations=7: def new generation total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000) eden space 49152K, 99% used [0x1ebd0000, 0x21bce430, 0x21bd0000) from space 6144K, 55% used [0x221d0000, 0x22527e10, 0x227d0000) to space 6144K, 0% used [0x21bd0000, 0x21bd0000, 0x221d0000) tenured generation total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000) the space 69632K, 3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000) compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000) the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000) ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000) rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000) 34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8: def new generation total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000) eden space 49152K, 0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000) from space 6144K, 55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000) to space 6144K, 0% used [0x221d0000, 0x221d0000, 0x227d0000) tenured generation total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000) the space 69632K, 4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000) compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000) the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000) ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000) rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000) } , 0.0757599 secs] -Xloggc:filename:与上面几个配合用,把相x志信息记录到文g以便分析?常见配置汇?堆设|?-Xms:初始堆大?-Xmx:最大堆大小 -XX:NewSize=n:讄q轻代大?-XX:NewRatio=n:讄q轻代和q老代的比倹{如:?Q表C年M与年老代比gؓ1Q?Q年M占整个年Mq老代和的1/4 -XX:SurvivorRatio=n:q轻代中EdenZ两个Survivor区的比倹{注意Survivor区有两个。如Q?Q表CEdenQSurvivor=3Q?Q一个Survivor区占整个q轻代的1/5 -XX:MaxPermSize=n:讄持久代大?攉器设|?-XX:+UseSerialGC:讄串行攉?-XX:+UseParallelGC:讄q行攉?-XX:+UseParalledlOldGC:讄q行q老代攉?-XX:+UseConcMarkSweepGC:讄q发攉?垃圾回收l计信息 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:filename q行攉器设|?-XX:ParallelGCThreads=n:讄q行攉器收集时使用的CPU数。ƈ行收集线E数?-XX:MaxGCPauseMillis=n:讄q行攉最大暂停时?-XX:GCTimeRatio=n:讄垃圾回收旉占程序运行时间的癑ֈ比。公式ؓ1/(1+n) q发攉器设|?-XX:+CMSIncrementalMode:讄为增量模式。适用于单CPU情况?-XX:ParallelGCThreads=n:讄q发攉器年M攉方式为ƈ行收集时Q用的CPU数。ƈ行收集线E数?/p>

四、调优ȝ

q轻代大选择 响应旉优先的应用:可能设大,直到接近pȝ的最低响应时间限ӞҎ实际情况选择Q。在此种情况下,q轻代收集发生的频率也是最的。同Ӟ减少到达q老代的对象?吞吐量优先的应用Q尽可能的设|大Q可能到达Gbit的程度。因为对响应旉没有要求Q垃圾收集可以ƈ行进行,一般适合8CPU以上的应用?q老代大小选择 响应旉优先的应用:q老代使用q发攉器,所以其大小需要小心设|,一般要考虑q发会话率和会话持箋旉{一些参数。如果堆讄了Q可以会造成内存片、高回收频率以及应用暂停而用传l的标记清除方式Q如果堆大了Q则需要较长的攉旉。最优化的方案,一般需要参考以下数据获得: q发垃圾攉信息 持久代ƈ发收集次?传统GC信息 花在q轻代和q老代回收上的旉比例 减少q轻代和q老代p的时_一般会提高应用的效?吞吐量优先的应用Q一般吞吐量优先的应用都有一个很大的q轻代和一个较的q老代。原因是Q这样可以尽可能回收掉大部分短期对象Q减中期的对象Q而年老代存N期存zd象?较小堆引L片问题 因ؓq老代的ƈ发收集器使用?记、清除算法,所以不会对堆进行压~。当攉器回收时Q他会把盔R的空间进行合qӞq样可以分配l较大的对象。但是,当堆I间较小Ӟq行一D|间以后, ׃出现“碎片”,如果q发攉器找不到_的空_那么q发攉器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如 下配|: -XX:+UseCMSCompactAtFullCollectionQ用ƈ发收集器Ӟ开启对q老代的压~?-XX:CMSFullGCsBeforeCompaction=0Q上面配|开启的情况下,q里讄多少ơFull GC后,对年老代q行压羃

本文链接Q?a href="http://www.tfdwme.live/post/422cd440.html">http://www.tfdwme.live/post/422cd440.htmlQ?a href="http://www.tfdwme.live/post/422cd440.html#comments">参与评论

]]>
go {待一l协E结束的实现方式 http://www.tfdwme.live/post/84cc3ac0.html http://www.tfdwme.live/post/84cc3ac0.html#comments http://www.tfdwme.live/post/84cc3ac0.html

go 提供?sync 包和 channel 来解军_E同步和通讯?/p>

方式 1:

sync.WaitGroup 是等待一l协E结束,sync.WaitGroup 只有 3 个方法,Add() d一个计敎ͼDone() 减去一个计敎ͼWait() d直到所有Q务完成?/p>

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup //定义一个同步等待的l?
func task(i int){
    fmt.Println("task...",i)
    //耗时操作dQ网l请求,d文g
    time.Sleep(time.Second)
    wg.Done() //减去一个计?}

func main(){
    for i:= 0;i<10;i++{
        wg.Add(1) //d一个计?        go task(i)
    }
    wg.Wait() //d直到所有Q务完?    fmt.Println("over")
}

q行l果Q?task… 9 task… 4 task… 6 task… 0 task… 7 task… 5 task… 1 task… 2 task… 8 task… 3

over

方式 2:

利用~冲信道 channel 协程之间通讯Q其d{待功能实现{待一l协E结束,不能保证?goroutine 按照序执行

package main

import (
    "fmt"
)

var ch = make(chan int,10)

func task(i int){
    fmt.Println("task...",i)
    ch <- i
}

func main(){
    for i:= 0;i<10;i++{
        go task(i)
    }
    for i:= 0;i<10;i++{
        <- ch
    } 
    fmt.Println("over")
}

q行l果Q?task… 9 task… 0 task… 1 task… 2 task… 6 task… 7 task… 3 task… 4 task… 8 task… 5

over

方式 3:

利用无缓冲的信道 channel 协程之间通讯Q其d{待功能实现{待一l协E结束,保证了其 goroutine 按照序执行

package main

import (
    "fmt"
    "time"
)

var ch = make(chan int)

func task(i int){
    fmt.Println("task...",i)
    time.Sleep(time.Second)
     <- ch
}

func main(){
    for i:= 0;i<10;i++{
        go task(i)
        ch <- i
    }
    fmt.Println("over")
}

q行l果Q?task… 0 task… 1 task… 2 task… 3 task… 4 task… 5 task… 6 task… 7 task… 8 task… 9 over

本文链接Q?a href="http://www.tfdwme.live/post/84cc3ac0.html">http://www.tfdwme.live/post/84cc3ac0.htmlQ?a href="http://www.tfdwme.live/post/84cc3ac0.html#comments">参与评论

]]>
totoָ