重要知识点
多进程和多线程都可以执行多个任务,线程是进程的一部分。
Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。
线程的特点是线程之间可以共享内存和变量,资源消耗少(不过在Unix环境中,多进程和多线程资源调度消耗差距不明显,Unix调度较快),缺点是线程之间的同步和加锁比较麻烦。
start()启动线程,join()阻塞当前线程,即使得在当前线程结束时,不会退出。Python中,默认情况下,如果不加join语句,那么主线程不会等到当前线程结束才结束,但却不会立即杀死该线程。
如果为线程实例添加t.setDaemon(True)之后,如果不加join语句,那么当主线程结束之后,会杀死子线程。
对于多线程来说,最大的特点就是线程之间可以共享数据,那么共享数据就会出现多线程同时更改一个变量,使用同样的资源,而出现死锁、数据错乱等情况。对于该问题,可以在访问某个资源之前,用Lock.acquire()锁住资源,访问之后,用Lock.release()释放资源。
当不想将变量共享给其他线程时,可以使用局部变量,但在函数中定义局部变量会使得在函数之间传递特别麻烦。可以使用ThreadLocal解决了全局变量需要枷锁,局部变量传递麻烦的两个问题。
Python 中两个库包含了 map 函数: multiprocessing 和它的子库 multiprocessing.dummy.dummy 。后者是multiprocessing 模块的完整克隆,唯一的不同在于 multiprocessing 作用于进程,而 dummy 模块作用于线程。
Python中,有一个GIL,即全局解释锁,该锁的存在保证在同一个时间只能有一个线程执行任务,也就是多线程并不是真正的并发,只是交替得执行。假如有10个线程炮在10核CPU上,当前工作的也只能是一个CPU上的线程。
Python多线程很适合用在IO密集型任务中。I/O密集型执行期间大部分是时间都用在I/O上,如数据库I/O,较少时间用在CPU计算上,对于计算密集型任务,应该使用Python多进程。
Python 的 Queue 模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列 PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用,可以使用队列来实现线程间的同步。
常用多线程写法
import threading, thread
import time
class MyThread(threading.Thread):
"""docstring for MyThread"""
def __init__(self, thread_id, name, counter) :
super(MyThread, self).__init__() #调用父类的构造函数
self.thread_id = thread_id
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(thread_name, delay, counter) :
while counter :
time.sleep(delay)
print "%s %s" % (thread_name, time.ctime(time.time()))
counter -= 1
def main():
#创建新的线程
thread1 = MyThread(1, "Thread-1", 1)
thread2 = MyThread(2, "Thread-2", 2)
#开启线程
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print "Exiting Main Thread"
if __name__ == '__main__':
main()