python模塊介紹-threading: 線程 管理併發操做

定義線程

最簡單的方法:使用target指定線程要執行的目標函數,再使用start()啓動。python

語法:編程

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})

group恆爲None,保留將來使用。target爲要執行的函數名。name爲線程名,默認爲Thread-N,一般使用默認便可。但服務器端程序線程功能不一樣時,建議命名。安全

#!/usr/bin/env python3
# coding=utf-8
import threading

def function(i):
    print ("function called by thread {0}".format(i))
threads = []

for i in range(5):
    t = threading.Thread(target=function , args=(i,))
    threads.append(t)
    t.start()
    t.join()

執行結果:服務器

$ ./threading_define.py 
function called by thread 0
function called by thread 1
function called by thread 2
function called by thread 3
function called by thread 4

肯定當前線程

#!/usr/bin/env python3
# coding=utf-8

import threading
import time

def first_function():
    print (threading.currentThread().getName()+ str(' is Starting \n'))
    time.sleep(3)
    print (threading.currentThread().getName()+ str( ' is Exiting \n'))
    
def second_function():
    print (threading.currentThread().getName()+ str(' is Starting \n'))
    time.sleep(2)
    print (threading.currentThread().getName()+ str( ' is Exiting \n'))
    
def third_function():
    print (threading.currentThread().getName()+\
    str(' is Starting \n'))
    time.sleep(1)
    print (threading.currentThread().getName()+ str( ' is Exiting \n'))
    
if __name__ == "__main__":
    t1 = threading.Thread(name='first_function', target=first_function)
    t2 = threading.Thread(name='second_function', target=second_function)
    t3 = threading.Thread(name='third_function',target=third_function)
    t1.start()
    t2.start()
    t3.start()

執行結果:數據結構

$ ./threading_name.py 
first_function is Starting 
second_function is Starting 
third_function is Starting 
third_function is Exiting 
second_function is Exiting 
first_function is Exiting


配合logging模塊一塊兒使用:app

#!/usr/bin/env python3
# coding=utf-8

import logging
import threading
import time

logging.basicConfig(
    level=logging.DEBUG,
    format='[%(levelname)s] (%(threadName)-10s) %(message)s',
    )
    
def worker():
    logging.debug('Starting')
    time.sleep(2)
    logging.debug('Exiting')
    
def my_service():
    logging.debug('Starting')
    time.sleep(3)
    logging.debug('Exiting')
    
t = threading.Thread(name='my_service', target=my_service)
w = threading.Thread(name='worker', target=worker)
w2 = threading.Thread(target=worker) # use default name
w.start()
w2.start()
t.start()

執行結果:dom

$ ./threading_names_log.py[DEBUG] (worker    ) Starting
[DEBUG] (Thread-1  ) Starting
[DEBUG] (my_service) Starting
[DEBUG] (worker    ) Exiting
[DEBUG] (Thread-1  ) Exiting
[DEBUG] (my_service) Exiting


在子類中使用線程

前面咱們的線程都是結構化編程的形式來建立。經過集成threading.Thread類也能夠建立線程。Thread類首先完成一些基本上初始化,而後調用它的run()。run()方法會會調用傳遞給構造函數的目標函數。函數

#!/usr/bin/env python3
# coding=utf-8

import logging
import threading
import time

exitFlag = 0

class myThread (threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
        
    def run(self):
        print ("Starting " + self.name)
        print_time(self.name, self.counter, 5)
        print ("Exiting " + self.name)
        
def print_time(threadName, delay, counter):
    while counter:
        if exitFlag:
            thread.exit()
        time.sleep(delay)
        print ("%s: %s" %(threadName, time.ctime(time.time())))
        counter -= 1
        
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start new Threads
thread1.start()
thread2.start()
print ("Exiting Main Thread")

執行結果:ui

$ ./threading_subclass.py 
Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Tue Sep 15 11:03:21 2015
Thread-2: Tue Sep 15 11:03:22 2015
Thread-1: Tue Sep 15 11:03:22 2015
Thread-1: Tue Sep 15 11:03:23 2015
Thread-2: Tue Sep 15 11:03:24 2015
Thread-1: Tue Sep 15 11:03:24 2015
Thread-1: Tue Sep 15 11:03:25 2015
Exiting Thread-1
Thread-2: Tue Sep 15 11:03:26 2015
Thread-2: Tue Sep 15 11:03:28 2015
Thread-2: Tue Sep 15 11:03:30 2015
Exiting Thread-2


python的內置數據結構好比列表和字典等是線程安全的,可是簡單數據類型好比整數和浮點數則不是線程安全的,要這些簡單數據類型的經過操做,就須要使用鎖。spa

#!/usr/bin/env python3
# coding=utf-8

import threading

shared_resource_with_lock = 0
shared_resource_with_no_lock = 0
COUNT = 100000
shared_resource_lock = threading.Lock()

####LOCK MANAGEMENT##
def increment_with_lock():
    global shared_resource_with_lock
    for i in range(COUNT):
        shared_resource_lock.acquire()
        shared_resource_with_lock += 1
        shared_resource_lock.release()
        
def decrement_with_lock():
    global shared_resource_with_lock
    for i in range(COUNT):
        shared_resource_lock.acquire()
        shared_resource_with_lock -= 1
        shared_resource_lock.release()
        ####NO LOCK MANAGEMENT ##
    
def increment_without_lock():
    global shared_resource_with_no_lock
    for i in range(COUNT):
        shared_resource_with_no_lock += 1
    
def decrement_without_lock():
    global shared_resource_with_no_lock
    for i in range(COUNT):
        shared_resource_with_no_lock -= 1
    
####the Main program
if __name__ == "__main__":
    t1 = threading.Thread(target = increment_with_lock)
    t2 = threading.Thread(target = decrement_with_lock)
    t3 = threading.Thread(target = increment_without_lock)
    t4 = threading.Thread(target = decrement_without_lock)
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t1.join()
    t2.join()
    t3.join()
    t4.join()
    print ("the value of shared variable with lock management is %s"\
    %shared_resource_with_lock)
    print ("the value of shared variable with race condition is %s"\
    %shared_resource_with_no_lock)

執行結果:

$ ./threading_lock.py 
the value of shared variable with lock management is 0
the value of shared variable with race condition is 0


又如:

import random
import threading
import time
logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )
                    
class Counter(object):
    def __init__(self, start=0):
        self.lock = threading.Lock()
        self.value = start
    def increment(self):
        logging.debug(time.ctime(time.time()))
        logging.debug('Waiting for lock')
        self.lock.acquire()
        try:
            pause = random.randint(1,3)
            logging.debug(time.ctime(time.time()))
            logging.debug('Acquired lock')            
            self.value = self.value + 1
            logging.debug('lock {0} seconds'.format(pause))
            time.sleep(pause)
        finally:
            self.lock.release()
def worker(c):
    for i in range(2):
        pause = random.randint(1,3)
        logging.debug(time.ctime(time.time()))
        logging.debug('Sleeping %0.02f', pause)
        time.sleep(pause)
        c.increment()
    logging.debug('Done')
counter = Counter()
for i in range(2):
    t = threading.Thread(target=worker, args=(counter,))
    t.start()
logging.debug('Waiting for worker threads')
main_thread = threading.currentThread()
for t in threading.enumerate():
    if t is not main_thread:
        t.join()
logging.debug('Counter: %d', counter.value)

執行結果:

$ python threading_lock.py 
(Thread-1  ) Tue Sep 15 15:49:18 2015
(Thread-1  ) Sleeping 3.00
(Thread-2  ) Tue Sep 15 15:49:18 2015
(MainThread) Waiting for worker threads
(Thread-2  ) Sleeping 2.00
(Thread-2  ) Tue Sep 15 15:49:20 2015
(Thread-2  ) Waiting for lock
(Thread-2  ) Tue Sep 15 15:49:20 2015
(Thread-2  ) Acquired lock
(Thread-2  ) lock 2 seconds
(Thread-1  ) Tue Sep 15 15:49:21 2015
(Thread-1  ) Waiting for lock
(Thread-2  ) Tue Sep 15 15:49:22 2015
(Thread-1  ) Tue Sep 15 15:49:22 2015
(Thread-2  ) Sleeping 2.00
(Thread-1  ) Acquired lock
(Thread-1  ) lock 1 seconds
(Thread-1  ) Tue Sep 15 15:49:23 2015
(Thread-1  ) Sleeping 2.00
(Thread-2  ) Tue Sep 15 15:49:24 2015
(Thread-2  ) Waiting for lock
(Thread-2  ) Tue Sep 15 15:49:24 2015
(Thread-2  ) Acquired lock
(Thread-2  ) lock 1 seconds
(Thread-1  ) Tue Sep 15 15:49:25 2015
(Thread-1  ) Waiting for lock
(Thread-1  ) Tue Sep 15 15:49:25 2015
(Thread-1  ) Acquired lock
(Thread-1  ) lock 2 seconds
(Thread-2  ) Done
(Thread-1  ) Done
(MainThread) Counter: 4

acquire()中傳入False值,能夠檢查是否得到了鎖。好比:

import logging
import threading
import time
logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )
                    
def lock_holder(lock):
    logging.debug('Starting')
    while True:
        lock.acquire()
        try:
            logging.debug('Holding')
            time.sleep(0.5)
        finally:
            logging.debug('Not holding')
            lock.release()
        time.sleep(0.5)
    return
                    
def worker(lock):
    logging.debug('Starting')
    num_tries = 0
    num_acquires = 0
    while num_acquires < 3:
        time.sleep(0.5)
        logging.debug('Trying to acquire')
        have_it = lock.acquire(0)
        try:
            num_tries += 1
            if have_it:
                logging.debug('Iteration %d: Acquired',
                              num_tries)
                num_acquires += 1
            else:
                logging.debug('Iteration %d: Not acquired',
                              num_tries)
        finally:
            if have_it:
                lock.release()
    logging.debug('Done after %d iterations', num_tries)
lock = threading.Lock()
holder = threading.Thread(target=lock_holder,
                          args=(lock,),
                          name='LockHolder')
holder.setDaemon(True)
holder.start()
worker = threading.Thread(target=worker,
                          args=(lock,),
                          name='Worker')
worker.start()

執行結果:

$ python threading_lock_noblock.py 
(LockHolder) Starting
(LockHolder) Holding
(Worker    ) Starting
(LockHolder) Not holding
(Worker    ) Trying to acquire
(Worker    ) Iteration 1: Acquired
(LockHolder) Holding
(Worker    ) Trying to acquire
(Worker    ) Iteration 2: Not acquired
(LockHolder) Not holding
(Worker    ) Trying to acquire
(Worker    ) Iteration 3: Acquired
(LockHolder) Holding
(Worker    ) Trying to acquire
(Worker    ) Iteration 4: Not acquired
(LockHolder) Not holding
(Worker    ) Trying to acquire
(Worker    ) Iteration 5: Acquired
(Worker    ) Done after 5 iterations

線程安全鎖

threading.RLock()
返回可重入鎖對象。重入鎖必須由得到它的線程釋放。一旦線程得到了重入鎖,同一線程不阻塞地再次得到,獲取以後必須釋放

一般一個線程只能獲取一次鎖:

import threading

lock = threading.Lock()

print 'First try :', lock.acquire()
print 'Second try:', lock.acquire(0)

執行結果:

$ python threading_lock_reacquire.py
First try : True
Second try: False

使用RLock能夠獲取屢次鎖:

import threading
lock = threading.RLock()
print 'First try :', lock.acquire()
print 'Second try:', lock.acquire(0)

執行結果:

python threading_rlock.py 
First try : True
Second try: 1
#!/usr/bin/env python3
# coding=utf-8
import threading
import time
class Box(object):
    lock = threading.RLock()
    def __init__(self):
        self.total_items = 0
    def execute(self,n):
        Box.lock.acquire()
        self.total_items += n
        Box.lock.release()
    def add(self):
        Box.lock.acquire()
        self.execute(1)
        Box.lock.release()
    def remove(self):
        Box.lock.acquire()
        self.execute(-1)
        Box.lock.release()
        
## These two functions run n in separate
## threads and call the Box's methods        
def adder(box,items):
    while items > 0:
        print ("adding 1 item in the box\n")
        box.add()
        time.sleep(5)
        items -= 1
        
def remover(box,items):
    while items > 0:
        print ("removing 1 item in the box")
        box.remove()
        time.sleep(5)
        items -= 1
        
## the main program build some
## threads and make sure it works
if __name__ == "__main__":
    items = 5
    print ("putting %s items in the box " % items)
    box = Box()
    t1 = threading.Thread(target=adder,args=(box,items))
    t2 = threading.Thread(target=remover,args=(box,items))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print ("%s items still remain in the box " % box.total_items)

執行結果:

$ python3 threading_rlock2.py 
putting 5 items in the box 
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
0 items still remain in the box
相關文章
相關標籤/搜索