好程式設計師分享迴圈內的回撥函式

好程式設計師IT發表於2019-04-22

   好程式設計師 分享 迴圈內的回撥函式 問題出現在迴圈體內的回撥函式,用一個很簡單的例子舉例:

   for x in xrange(3):

1.  <p><font size="3">  print "requests begin:%s"%x</font></p>

2.  <p><font size="3">  def callback(respon):</font></p>

3.  <p><font size="3">  print x</font></p>

4.  <p><font size="3">  print respon.body</font></p>

5.  <p><font size="3">  client.fetch("%s" % x, callback)</font></p>


  此例子忽略了等待回撥函式完成的 wait實現(不實現這個會導致作為單個檔案執行的時候,還沒獲得結果就退出了),在tornado.testing中的AsyncTestCase提供了相關功能
  httpbin.org/get這個地址的作用是返回了請求的json物件,形如:
   {

1.  <p><font size="3">  "args": {</font></p>

2.  <p><font size="3">  "x": "0"</font></p>

3.  <p><font size="3">  },</font></p>

4.  <p><font size="3">  "headers": {</font></p>

5.  <p><font size="3">  "Accept-Encoding": "gzip",</font></p>

6.  <p><font size="3">  "Connection": "close",</font></p>

7.  <p><font size="3">  "Host": "httpbin.org",</font></p>

8.  <p><font size="3">  "X-Request-Id": "95df3c15-7ed0-4a6d-830d-fb9629e66515"</font></p>

9.  <p><font size="3">  },</font></p>

10.  <p><font size="3">  "origin": "192.81.129.91",</font></p>

11.  <p><font size="3">  "url": "0"</font></p>

12.  <p><font size="3">  }</font></p>


  但實際上,由於回撥函式特殊的特性:訪問閉包內區域性變數的當前值。易知,在第一個請求
   url返回時,迴圈早已結束,此時的x已經為2,因此實際上雖然httpbin.org返回的json告訴我們,get引數裡的x為0,但閉包內訪問到的x已經是2了
  解決方法我想了兩個,一個是利用回撥函式構造時的變數空間,在建構函式時即產生這個引數,形如:
   client = AsyncHTTPClient(self.io_loop)

1.  <p><font size="3">  for x in xrange(3):</font></p>

2.  <p><font size="3">  def callback(respon,num=x):</font></p>

3.  <p><font size="3">  print x, num</font></p>

4.  <p><font size="3">  print respon.body</font></p>

5.  <p><font size="3">  if num == 2:</font></p>

6.  <p><font size="3">  self.stop()</font></p>

7.  <p><font size="3">  client.fetch("%s" % x, wrap(x))</font></p>


  一種是再包一層閉包 (這層閉包也可以放在for外面):
   client = AsyncHTTPClient(self.io_loop)

1.  <p><font size="3">  for x in xrange(3):</font></p>

2.  <p><font size="3">  def wrap(number):</font></p>

3.  <p><font size="3">  num = number</font></p>

4.  <p><font size="3">  def callback(respon):</font></p>

5.  <p><font size="3">  print x, num</font></p>

6.  <p><font size="3">  print respon.body</font></p>

7.  <p><font size="3">  if num == 2:</font></p>

8.  <p><font size="3">  self.stop()</font></p>

9.  <p><font size="3">  return callback</font></p>

10.  <p><font size="3">  client.fetch("%s" % x, wrap(x))</font></p>

11.  <p><font size="3">  #wrap放在for外面:</font></p>

12.  <p><font size="3">  client = AsyncHTTPClient(self.io_loop)</font></p>

13.  <p><font size="3">  def wrap(number):</font></p>

14.  <p><font size="3">  num = number</font></p>

15.  <p><font size="3">  def callback(respon):</font></p>

16.  <p><font size="3">  print x, num</font></p>

17.  <p><font size="3">  print respon.body</font></p>

18.  <p><font size="3">  if num == 2:</font></p>

19.  <p><font size="3">  self.stop()</font></p>

20.  <p><font size="3">  return callback</font></p>

21.  <p><font size="3">  for x in xrange(3):</font></p>

22.  <p><font size="3">  client.fetch("%s" % x,   wrap(x))</font></p>


  思索了一下,閉包的記憶體佔用問題應當是不可避免的 ?當迴圈體的每一項(x)是一個大記憶體物件時,記憶體佔用等同於不用迭代器用列表進行迴圈,除了這兩種不知道還有沒有更優雅的解決方案。。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2642152/,如需轉載,請註明出處,否則將追究法律責任。

相關文章