Python Multi thread

一個簡單的MULTI THREAD


from threading import Thread

def add_100():
 tmp = 0
 for i in range(0,100):
  tmp += i
 print tmp

def add_2000():
 tmp = 0
 for i in range(0,2000):
  tmp += i
 print tmp

threads = []
for func in [add_100, add_2000]:
   threads.append(Thread(target=func))
   threads[-1].start()

for thread in threads:
  
   thread.join()

試一下LOCK 之 無LOCK

from threading import Lock, Thread
import random, time
lock = Lock()
g = 0

def add_1000():

 global g
 #lock.acquire()
 for i in range(0,5):
  time.sleep(random.randrange(2, 5))
  g += 1
  print str(g) + "\n"
   #lock.release()

def add_2000():
 global g
 #lock.acquire()
 for i in range(0,5):
  time.sleep(random.randrange(2, 5))
  g += 10
  print str(g) + "\n"
 #lock.release()

threads = []
for func in [add_1000, add_2000]:
 threads.append(Thread(target=func))
 threads[-1].start()

for thread in threads:
 thread.join()

結果

1
11
21
22
32
33
43
44
54
55

g 這個參數被兩個thread 同時更動。


試一下LOCK 之 有LOCK

from threading import Lock, Thread
import random, time
lock = Lock()
g = 0

def add_1000():

 global g
 lock.acquire()
 for i in range(0,5):
  time.sleep(random.randrange(2, 5))
  g += 1
  print str(g) + "\n"
        lock.release()

def add_2000():
 global g
 lock.acquire()
 for i in range(0,5):
  time.sleep(random.randrange(2, 5))
  g += 10
  print str(g) + "\n"
 lock.release()

threads = []
for func in [add_1000, add_2000]:
 threads.append(Thread(target=func))
 threads[-1].start()

for thread in threads:
 thread.join()

結果

1
2
3
4
5
15
25
35
45
55

試試看RLock


from threading import Lock, Thread, RLock
import random, time
lock = RLock()
g = 0

def add_1000():

 global g
 
 for i in range(0,5):
  lock.acquire()
  time.sleep(random.randrange(2, 5))
  g += 1
  print str(g) + "\n"
 
 lock.release()
 lock.release()
 lock.release()
 lock.release()
 lock.release()


def add_2000():
 global g
 lock.acquire()
 for i in range(0,5):
  time.sleep(random.randrange(2, 5))
  g += 10
  print str(g) + "\n"
 lock.release()

threads = []
for func in [add_1000, add_2000]:
 threads.append(Thread(target=func))
 threads[-1].start()

for thread in threads:
 thread.join()



我們把lock.acquire()放在for回圈中,如果lock=Lock(),第一個回圈就會停住了。
因為Lock()一定需要lock.acquire()配一個lock.release()。
如果把lock = RLock()。lock.acquire()與lock.release()就可以如上例,重覆多次acquire, 再一次全部一起release()。

EVENTS


from threading import Lock, Thread, Event
import random, time
lock = Lock()
e = Event()
g = 0

def add_1000(e):

 global g
 for i in range(0,5):
  g += 1
  print str(g) + "\n"
  e.wait()
  print "yes go"
  e.clear()

def add_2000(e):
 global g
 
 for i in range(0,5):
  g += 10
  print str(g) + "\n"
  e.set()
 
threads = []
for func in [add_1000, add_2000]:
 threads.append(Thread(target=func, args=(event,)))
 threads[-1].start()

for thread in threads:
 thread.join()

結果
1
11
21
yes go
31
32
42
yes go
52
53
yes go
54

Event可以讓兩個thread構通, 藉由wait與set,由event.wait()等待另一個thread對event下set。原本wait就會解除。
由上例,可以看出add_2000會不斷送出event.set()讓event.wait()往下走。
本來期待可以出現
1
11
yes go
12
22
yes go
23
33
yes go
34
44
yes go
45
55
可以發現"yes go"只出現三次,因為add_2000送的set是不斷的送出,而add_1000的wait還沒有跑到。

Condition


from threading import Lock, Thread, Event,Condition
import random, time
lock = Lock()
e = Event()
c = Condition()
g = 0

def add_1000(c):

 global g
 for i in range(0,5):
  c.acquire()
  g += 1
  c.wait()
  g += 1
  print "yes go"
  print str(g) + "\n"
  c.release()

def add_2000(c):
 global g
 
 for i in range(0,5):
  c.acquire()
  g += 10
  print str(g) + "\n"
  c.notify()
  c.release()
 
threads = []
for func in [add_1000, add_2000]:
 threads.append(Thread(target=func, args=(con,)))
 threads[-1].start()

for thread in threads:
 thread.join()

結果

11

21

yes go
22

32

43

53

yes go
54

結果差不多,其實condition就是EVENT + LOCK, 以這個角度來說,CONDITON提供的是多個THREAD等待,等到條件成立,就會去使用某些共用的資源。
而EVENT則比較像提供的是多個THREAD等待,等到條件成立,獨立去做某個自的事。
但我們能不能把EVENT寫的很像CONDITION,當然也可以。不就是EVENT+LOCK麼!

留言

這個網誌中的熱門文章

python 找圖自動點擊

Python pyserial 抓取系統內的 COM PORT

VBA EXCEL 工作表變化 馬上執行 的作法 Worksheet_Change