close

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

  1. #!/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 程式
  1. import RPi.GPIO as GPIO  
  2. GPIO.setmode(GPIO.BCM)  

    import threading
    import time
    import RPi.GPIO as GPIO

    GPIO.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 = True

                    while 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&gt;")

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中斷處理
  1. #!/usr/bin/env python2.7  
  2. # script by Alex Eames http://RasPi.tv  
  3. # http://RasPi.tv/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3  
  4. import RPi.GPIO as GPIO  
  5. GPIO.setmode(GPIO.BCM)  
  6.   
  7. # GPIO 23 & 17 set up as inputs, pulled up to avoid false detection.  
  8. # Both ports are wired to connect to GND on button press.  
  9. # So we'll be setting up falling edge detection for both  
  10. GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)  
  11. GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)  
  12.   
  13. # GPIO 24 set up as an input, pulled down, connected to 3V3 on button press  
  14. GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)  
  15.   
  16. # now we'll define two threaded callback functions  
  17. # these will run in another thread when our events are detected  
  18. def my_callback(channel):  
  19.     print "falling edge detected on 17"  
  20.   
  21. def my_callback2(channel):  
  22.     print "falling edge detected on 23"  
  23.   
  24. print "Make sure you have a button connected so that when pressed"  
  25. print "it will connect GPIO port 23 (pin 16) to GND (pin 6)\n"  
  26. print "You will also need a second button connected so that when pressed"  
  27. print "it will connect GPIO port 24 (pin 18) to 3V3 (pin 1)\n"  
  28. print "You will also need a third button connected so that when pressed"  
  29. print "it will connect GPIO port 17 (pin 11) to GND (pin 14)"  
  30. raw_input("Press Enter when ready\n>")  
  31.   
  32. # when a falling edge is detected on port 17, regardless of whatever   
  33. # else is happening in the program, the function my_callback will be run  
  34. GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=300)  
  35.   
  36. # when a falling edge is detected on port 23, regardless of whatever   
  37. # else is happening in the program, the function my_callback2 will be run  
  38. # 'bouncetime=300' includes the bounce control written into interrupts2a.py  
  39. GPIO.add_event_detect(23, GPIO.FALLING, callback=my_callback2, bouncetime=300)  
  40.   
  41. try:  
  42.     print "Waiting for rising edge on port 24"  
  43.     GPIO.wait_for_edge(24, GPIO.RISING)  
  44.     print "Rising edge detected on port 24. Here endeth the third lesson."  
  45.   
  46. except KeyboardInterrupt:  
  47.     GPIO.cleanup()       # clean up GPIO on CTRL+C exit  
  48. GPIO.cleanup()           # clean up GPIO on normal exit  

第二種為 threaded callback 中斷處理

  1. #!/usr/bin/env python2.7  
  2. # script by Alex Eames http://RasPi.tv  
  3.   
  4. import RPi.GPIO as GPIO  
  5. GPIO.setmode(GPIO.BCM)  
  6.   
  7. # GPIO 23 & 24 set up as inputs. One pulled up, the other down.  
  8. # 23 will go to GND when button pressed and 24 will go to 3V3 (3.3V)  
  9. # this enables us to demonstrate both rising and falling edge detection  
  10. GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)  
  11. GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)  
  12.   
  13. # now we'll define the threaded callback function  
  14. # this will run in another thread when our event is detected  
  15. def my_callback(channel):  
  16.     print "Rising edge detected on port 24 - even though, in the main thread,"  
  17.     print "we are still waiting for a falling edge - how cool?\n"  
  18.   
  19. print "Make sure you have a button connected so that when pressed"  
  20. print "it will connect GPIO port 23 (pin 16) to GND (pin 6)\n"  
  21. print "You will also need a second button connected so that when pressed"  
  22. print "it will connect GPIO port 24 (pin 18) to 3V3 (pin 1)"  
  23. raw_input("Press Enter when ready\n>")  
  24.   
  25. # The GPIO.add_event_detect() line below set things up so that  
  26. # when a rising edge is detected on port 24, regardless of whatever   
  27. # else is happening in the program, the function "my_callback" will be run  
  28. # It will happen even while the program is waiting for  
  29. # a falling edge on the other button.  
  30. GPIO.add_event_detect(24, GPIO.RISING, callback=my_callback)  
  31.   
  32. try:  
  33.     print "Waiting for falling edge on port 23"  
  34.     GPIO.wait_for_edge(23, GPIO.FALLING)  
  35.     print "Falling edge detected. Here endeth the second lesson."  
  36.   
  37. except KeyboardInterrupt:  
  38.     GPIO.cleanup()       # clean up GPIO on CTRL+C exit  
  39. GPIO.cleanup()           # clean up GPIO on normal exit  

<3>為Multiple threaded callback 中斷處理

  1. # script by Alex Eames http://RasPi.tv  
  2. # http://RasPi.tv/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3  
  3. import RPi.GPIO as GPIO  
  4. GPIO.setmode(GPIO.BCM)  
  5.   
  6. # GPIO 23 & 17 set up as inputs, pulled up to avoid false detection.  
  7. # Both ports are wired to connect to GND on button press.  
  8. # So we'll be setting up falling edge detection for both  
  9. GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)  
  10. GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)  
  11.   
  12. # GPIO 24 set up as an input, pulled down, connected to 3V3 on button press  
  13. GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)  
  14.   
  15. # now we'll define two threaded callback functions  
  16. # these will run in another thread when our events are detected  
  17. def my_callback(channel):  
  18.     print "falling edge detected on 17"  
  19.   
  20. def my_callback2(channel):  
  21.     print "falling edge detected on 23"  
  22.   
  23. print "Make sure you have a button connected so that when pressed"  
  24. print "it will connect GPIO port 23 (pin 16) to GND (pin 6)\n"  
  25. print "You will also need a second button connected so that when pressed"  
  26. print "it will connect GPIO port 24 (pin 18) to 3V3 (pin 1)\n"  
  27. print "You will also need a third button connected so that when pressed"  
  28. print "it will connect GPIO port 17 (pin 11) to GND (pin 14)"  
  29. raw_input("Press Enter when ready\n>")  
  30.   
  31. # when a falling edge is detected on port 17, regardless of whatever   
  32. # else is happening in the program, the function my_callback will be run  
  33. GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=300)  
  34.   
  35. # when a falling edge is detected on port 23, regardless of whatever   
  36. # else is happening in the program, the function my_callback2 will be run  
  37. # 'bouncetime=300' includes the bounce control written into interrupts2a.py  
  38. GPIO.add_event_detect(23, GPIO.FALLING, callback=my_callback2, bouncetime=300)  
  39.   
  40. try:  
  41.     print "Waiting for rising edge on port 24"  
  42.     GPIO.wait_for_edge(24, GPIO.RISING)  
  43.     print "Rising edge detected on port 24. Here endeth the third lesson."  
  44.   
  45. except KeyboardInterrupt:  
  46.     GPIO.cleanup()       # clean up GPIO on CTRL+C exit  
  47. 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 就會開始工作。

  1. #!/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'


     
  1. 在 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

 

arrow
arrow

    stanley 發表在 痞客邦 留言(0) 人氣()