threads稱做輕量process,他們不需要很多的記憶體空間且一個proces內的數個threads可以共有資料空間和互相溝通。
執行數個threads 相當於同時執行數個不同的程式。
Starting a New Thread
thread.start_new_thread ( function, args[, kwargs] )
Example
#!/usr/bin/python import thread import time # Define a function for the thread def print_time( threadName, delay): count = 0 while count < 5: time.sleep(delay) count += 1 print "%s: %s" % ( threadName, time.ctime(time.time()) ) # Create two threads as follows try: thread.start_new_thread( print_time, ("Thread-1", 2, ) ) thread.start_new_thread( print_time, ("Thread-2", 4, ) ) except: print "Error: unable to start thread" while 1: pass
結果:
Thread-1: Thu Jan 22 15:42:17 2009 Thread-1: Thu Jan 22 15:42:19 2009 Thread-2: Thu Jan 22 15:42:19 2009 Thread-1: Thu Jan 22 15:42:21 2009 Thread-2: Thu Jan 22 15:42:23 2009 Thread-1: Thu Jan 22 15:42:23 2009 Thread-1: Thu Jan 22 15:42:25 2009 Thread-2: Thu Jan 22 15:42:27 2009 Thread-2: Thu Jan 22 15:42:31 2009 Thread-2: Thu Jan 22 15:42:35 2009
The Threading Module
在Python 2.4以上使用較新的Threading module 而不使用前面的thread module。Threading module 除了以前的 thread module 方法外更提供額外的方法
-
threading.activeCount(): Returns the number of thread objects that are active.
-
threading.currentThread(): Returns the number of thread objects in the caller's thread control.
-
threading.enumerate(): Returns a list of all thread objects that are currently active.
除了method,,還有thread 類別的implements
-
run(): The run() method is the entry point for a thread.
-
start(): The start() method starts a thread by calling the run method.
-
join([time]): The join() waits for threads to terminate.
-
isAlive(): The isAlive() method checks whether a thread is still executing.
-
getName(): The getName() method returns the name of a thread.
-
setName(): The setName() method sets the name of a thread.
Creating Thread Using Threading Module
-
Define a new subclass of the Thread class.
-
Override the __init__(self [,args]) method to add additional arguments.
-
Then, override the run(self [,args]) method to implement what the thread should do when started.
-
Example
-
#!/usr/bin/python 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, counter, delay): while counter: if exitFlag: threadName.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"
結果:
Starting Thread-1 Starting Thread-2 Exiting Main Thread Thread-1: Thu Mar 21 09:10:03 2013 Thread-1: Thu Mar 21 09:10:04 2013 Thread-2: Thu Mar 21 09:10:04 2013 Thread-1: Thu Mar 21 09:10:05 2013 Thread-1: Thu Mar 21 09:10:06 2013 Thread-2: Thu Mar 21 09:10:06 2013 Thread-1: Thu Mar 21 09:10:07 2013 Exiting Thread-1 Thread-2: Thu Mar 21 09:10:08 2013 Thread-2: Thu Mar 21 09:10:10 2013 Thread-2: Thu Mar 21 09:10:12 2013 Exiting Thread-2
Synchronizing Threads
使用下面的method 同步thread
(1)Lock() method: returns the new lock.
(2)Racquire(blocking) method :force threads to run synchronously. The optional blocking parameter enables you to control whether the thread waits to acquire the lock.If blocking is set to 0, the thread returns immediately with a 0 value if the lock cannot be acquired and with a 1 if the lock was acquired. If blocking is set to 1, the thread blocks and wait for the lock to be released.
(3)release() method of the new lock object is used to release the lock when it is no longer required.
Example
-
#!/usr/bin/python import threading import time 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 # Get lock to synchronize threads threadLock.acquire() print_time(self.name, self.counter, 3) # Free lock to release next thread threadLock.release() def print_time(threadName, delay, counter): while counter: time.sleep(delay) print "%s: %s" % (threadName, time.ctime(time.time())) counter -= 1 threadLock = threading.Lock() threads = [] # Create new threads thread1 = myThread(1, "Thread-1", 1) thread2 = myThread(2, "Thread-2", 2) # Start new Threads thread1.start() thread2.start() # Add threads to thread list threads.append(thread1) threads.append(thread2) # Wait for all threads to complete for t in threads: t.join() print "Exiting Main Thread"
結果:
Starting Thread-1 Starting Thread-2 Thread-1: Thu Mar 21 09:11:28 2013 Thread-1: Thu Mar 21 09:11:29 2013 Thread-1: Thu Mar 21 09:11:30 2013 Thread-2: Thu Mar 21 09:11:32 2013 Thread-2: Thu Mar 21 09:11:34 2013 Thread-2: Thu Mar 21 09:11:36 2013 Exiting Main Thread
Threading & GPIO 程式
- import RPi.GPIO as GPIO
- GPIO.setmode(GPIO.BCM)
import threading
import time
import RPi.GPIO as GPIOGPIO.setmode(GPIO.BOARD)
class Button(threading.Thread):
def __init__(self, channel):
threading.Thread.__init__(self)
self._pressed = False
self.channel = channel
GPIO.setup(self.channel, GPIO.IN)
self.deamon = True
self.start()def run(self):
previous = None
while 1:
current = GPIO.input(self.channel)
time.sleep(0.01)if current is False and previous is True:
self._pressed = Truewhile self._pressed:
time.sleep(0.05)previous = current
def onButtonPress():
print("btn presdsed")button = Button(36)
while True:
name = input('Enter a Name:')if name.upper() == ('Q'):
break
print('hello', name)if button.pressed():
onButtonPress()
RPi.GPIO update and detecting BOTH rising and falling edges
#!/usr/bin/env python2.7
# demo of "BOTH" bi-directional edge detection
import RPi.GPIO as GPIO
from time import sleep # this lets us have a time delay (see line 12)
GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering
GPIO.setup(25, GPIO.IN) # set GPIO25 as input (button)
# Define a threaded callback function to run in another thread when events are detected
def my_callback(channel):
if GPIO.input(25): # if port 25 == 1
print "Rising edge detected on 25"
else: # if port 25 != 1
print "Falling edge detected on 25"
# when a changing edge is detected on port 25, regardless of whatever
# else is happening in the program, the function my_callback will be run
GPIO.add_event_detect(25, GPIO.BOTH, callback=my_callback)
print "Program will finish after 30 seconds or if you press CTRL+C\n"
print "Make sure you have a button connected, pulled down through 10k resistor"
print "to GND and wired so that when pressed it connects"
print "GPIO port 25 (pin 22) to GND (pin 6) through a ~1k resistor\n"
print "Also put a 100 nF capacitor across your switch for hardware debouncing"
print "This is necessary to see the effect we're looking for"
raw_input("Press Enter when ready\n>")
try:
print "When pressed, you'll see: Rising Edge detected on 25"
print "When released, you'll see: Falling Edge detected on 25"
sleep(30) # wait 30 seconds
print "Time's up. Finished!"
finally: # this block will run no matter how the try block exits
GPIO.cleanup() # clean up after yourself
#--------------- 我收集下面在Raspberry Pi 中可以使用的中斷處理方式。 在Raspberry Pi 中中斷處理可用下面方式。一種為GPIO中斷處理, 一種為 threaded callback 中斷處理方式 。 第一種為GPIO中斷處理
- #!/usr/bin/env python2.7
- # script by Alex Eames http://RasPi.tv
- # http://RasPi.tv/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3
- import RPi.GPIO as GPIO
- GPIO.setmode(GPIO.BCM)
- # GPIO 23 & 17 set up as inputs, pulled up to avoid false detection.
- # Both ports are wired to connect to GND on button press.
- # So we'll be setting up falling edge detection for both
- GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
- GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
- # GPIO 24 set up as an input, pulled down, connected to 3V3 on button press
- GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
- # now we'll define two threaded callback functions
- # these will run in another thread when our events are detected
- def my_callback(channel):
- print "falling edge detected on 17"
- def my_callback2(channel):
- print "falling edge detected on 23"
- print "Make sure you have a button connected so that when pressed"
- print "it will connect GPIO port 23 (pin 16) to GND (pin 6)\n"
- print "You will also need a second button connected so that when pressed"
- print "it will connect GPIO port 24 (pin 18) to 3V3 (pin 1)\n"
- print "You will also need a third button connected so that when pressed"
- print "it will connect GPIO port 17 (pin 11) to GND (pin 14)"
- raw_input("Press Enter when ready\n>")
- # when a falling edge is detected on port 17, regardless of whatever
- # else is happening in the program, the function my_callback will be run
- GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=300)
- # when a falling edge is detected on port 23, regardless of whatever
- # else is happening in the program, the function my_callback2 will be run
- # 'bouncetime=300' includes the bounce control written into interrupts2a.py
- GPIO.add_event_detect(23, GPIO.FALLING, callback=my_callback2, bouncetime=300)
- try:
- print "Waiting for rising edge on port 24"
- GPIO.wait_for_edge(24, GPIO.RISING)
- print "Rising edge detected on port 24. Here endeth the third lesson."
- except KeyboardInterrupt:
- GPIO.cleanup() # clean up GPIO on CTRL+C exit
- GPIO.cleanup() # clean up GPIO on normal exit
第二種為 threaded callback 中斷處理
- #!/usr/bin/env python2.7
- # script by Alex Eames http://RasPi.tv
- import RPi.GPIO as GPIO
- GPIO.setmode(GPIO.BCM)
- # GPIO 23 & 24 set up as inputs. One pulled up, the other down.
- # 23 will go to GND when button pressed and 24 will go to 3V3 (3.3V)
- # this enables us to demonstrate both rising and falling edge detection
- GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
- GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
- # now we'll define the threaded callback function
- # this will run in another thread when our event is detected
- def my_callback(channel):
- print "Rising edge detected on port 24 - even though, in the main thread,"
- print "we are still waiting for a falling edge - how cool?\n"
- print "Make sure you have a button connected so that when pressed"
- print "it will connect GPIO port 23 (pin 16) to GND (pin 6)\n"
- print "You will also need a second button connected so that when pressed"
- print "it will connect GPIO port 24 (pin 18) to 3V3 (pin 1)"
- raw_input("Press Enter when ready\n>")
- # The GPIO.add_event_detect() line below set things up so that
- # when a rising edge is detected on port 24, regardless of whatever
- # else is happening in the program, the function "my_callback" will be run
- # It will happen even while the program is waiting for
- # a falling edge on the other button.
- GPIO.add_event_detect(24, GPIO.RISING, callback=my_callback)
- try:
- print "Waiting for falling edge on port 23"
- GPIO.wait_for_edge(23, GPIO.FALLING)
- print "Falling edge detected. Here endeth the second lesson."
- except KeyboardInterrupt:
- GPIO.cleanup() # clean up GPIO on CTRL+C exit
- GPIO.cleanup() # clean up GPIO on normal exit
<3>為Multiple threaded callback 中斷處理
- # script by Alex Eames http://RasPi.tv
- # http://RasPi.tv/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3
- import RPi.GPIO as GPIO
- GPIO.setmode(GPIO.BCM)
- # GPIO 23 & 17 set up as inputs, pulled up to avoid false detection.
- # Both ports are wired to connect to GND on button press.
- # So we'll be setting up falling edge detection for both
- GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
- GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
- # GPIO 24 set up as an input, pulled down, connected to 3V3 on button press
- GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
- # now we'll define two threaded callback functions
- # these will run in another thread when our events are detected
- def my_callback(channel):
- print "falling edge detected on 17"
- def my_callback2(channel):
- print "falling edge detected on 23"
- print "Make sure you have a button connected so that when pressed"
- print "it will connect GPIO port 23 (pin 16) to GND (pin 6)\n"
- print "You will also need a second button connected so that when pressed"
- print "it will connect GPIO port 24 (pin 18) to 3V3 (pin 1)\n"
- print "You will also need a third button connected so that when pressed"
- print "it will connect GPIO port 17 (pin 11) to GND (pin 14)"
- raw_input("Press Enter when ready\n>")
- # when a falling edge is detected on port 17, regardless of whatever
- # else is happening in the program, the function my_callback will be run
- GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=300)
- # when a falling edge is detected on port 23, regardless of whatever
- # else is happening in the program, the function my_callback2 will be run
- # 'bouncetime=300' includes the bounce control written into interrupts2a.py
- GPIO.add_event_detect(23, GPIO.FALLING, callback=my_callback2, bouncetime=300)
- try:
- print "Waiting for rising edge on port 24"
- GPIO.wait_for_edge(24, GPIO.RISING)
- print "Rising edge detected on port 24. Here endeth the third lesson."
- except KeyboardInterrupt:
- GPIO.cleanup() # clean up GPIO on CTRL+C exit
- GPIO.cleanup() # clean up GPIO on normal exit
最後一個很實用的程式應用架構,可以參考的是Pooling Threads
Pooling Threads
有時侯我們建立太多 thread 時可能會造成系統(或程式)效能變差,
例如說我們只想建立兩個 threads,可是我們有十件工作要做,那麼我們就可以用排程的概念來實做。
在程式的一開始先把兩個 thread 建好,然後利用 python 的 Queue module去做pool的動作,把十件工作的資料都 put 進 Queue。
在 thread function 裡面會去 get Queue 的資料,只要 get 到thread 就會開始工作。
#!/usr/bin/python
#-*- coding:utf-8 -*-
from threading import *
import Queue
import time
class MyThread(Thread):
def ___init__(self, condition):
Thread.__init__(self)
self.cond = condition
def run(self):
print '{0} start\r\n'.format(self.getName())
global cnt
while (True):
id = threadPool.get()
if id != None:
self.cond.acquire()
print '{0}_{1}'.format(self.getName(), id)
for x in xrange(101):
cnt += x
time.sleep(2)
print 'cnt = {0}\r\n'.format(cnt)
cnt = 0
self.cond.release()
threadPool.task_done()
threadPool = Queue.Queue(0)
condition = Condition()
cnt = 0
for i in xrange(2):
MyThread(condition).start()
for i in xrange(10):
threadPool.put(i)
threadPool.join()
print 'done'
- 在 thread function 最後呼叫 task_done() 是為了讓 Queue 知道這一個工作已經完成,
是給 Queue.join() 作為參考。
如果這些工作會存取到相同的資源,
還是記得要用 Lock 保護。
資料來源:
(1) http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3
(2) http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-2
(3)http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio
(4)http://robsraspberrypi.blogspot.tw/2016/01/raspberry-pi-python-threading.html
(5)https://www.tutorialspoint.com/python/python_multithreading.htm
(6)http://robsraspberrypi.blogspot.tw/2016/01/raspberry-pi-python-threading.html
(7)RPi.GPIO update and detecting BOTH rising and falling edges
(8)http://raspi.tv/rpi-gpio
(9)http://skiesblog.blogspot.tw/2010/01/threading-in-python.html
留言列表