本文章参考自书籍Python程序员面试宝典
1、 任务?进程?线程?
1、首先我们理解一下什么是进程?什么是线程?
操作系统同时运行多个任务。一个任务就是一个进程。
进程就是我们运行的程序。这是我们的电脑运行的任务管理器。
对于线程而言,线程是进程的基本单位,一个进程至少有一个线程,但是如果一个进程只有一个线程的哈,那么这个线程一般被叫做主线程。
2、 thread创建新线程
Python提供多线程模块thread和threading,以及队列Queue,其中thread是比较基础的,不容易控制,而且thread参看底层堆栈内存,所以一般我们都是用threading。
下面就是用thread模块中的start_new_thread函数来产生新线程。
# 使用thread的start_new_thread创建新线程
import _thread
import time
def print_time(threadName,delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print("%s : %s"%(threadName,time.ctime(time.time())))
# 创建两个线程
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.exit()函数来抛出系统异常(SystemExitexception),然后就可以退出线程。
3、threading 创建线程
Python的标准库中thread提供的是比较低级,原始的线程以及一个简单的锁。
threading模块提供的方法包括:
threading.currentThread(): | 返回当前线程变量 |
---|---|
threading.enumerate(): | 返回一个正在运行的线程list |
threading.activeCount(): | 返回正在运行的线程数量 |
如何用threading创建新线程?
自定义一个threading.Thread的类,然后重写__init__ 方法和run方法。
# thread提供一些比较低级别的,原始线程以及一个简单的锁
import threading
import time
exitFlag = 0
# 集成父类 threading.Thread
# noinspection PyStatementEffect
class myThread(threading.Thread):
def __init__(self,threadID,name,counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
# 把要执行的代码写到run函数里面,线程在创建之后直接运行run函数
def run(self):
print("starting"+self.name)
print_time(self.name,self.counter,5)
#print_time(self.name,self.counter,5)
print("Exiting"+self.name)
def print_time(threadName,delay,counter):
while counter:
if exitFlag:
(threading.Thread).exit()
time.sleep(delay)
print("%s:%s"%(threadName,time.ctime(time.time())))
counter -= 1
# 创建新线程
thread1 = myThread(1,"Thread-1",1)
thread2 = myThread(2,"Thread-2",2)
# 开启线程
thread1.start()
thread2.start()
print("Exiting Main Thread")
运行结果:
4、如何保持线程同步?
如果多个线程对某个数据修改,则可以出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。
使用thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需求每次只允许一个线程操作的数据,可以将其操作放在acquire和release之间。
多线程的优势在于可以同时完成多个任务,但是当线程需要数据共享的时候,可能存在数据不同步的问题。
"""
多个线程如果对于某个数据修改,则可以产生不可预料的结果为了保证某个数据的正确性,就需要对某个线程进行同步
"""
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)
# 获得锁,成功获得锁定后返回True
# 可选的timeout 参数不填时候将一直阻塞,直到锁定
# 否则超时后将返回false
threadLock.acquire()
print_time(self.name,self.counter,3)
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 = []
# 创建新线程
thread1 = myThread(1,"Thread-1",1)
thread2 = myThread(2,"Thread-2",2)
# 开启新线程
thread1.start()
thread2.start()
# 添加新线程到线程列表
threads.append(thread1)
threads.append(thread2)
# 等待所有的线程完成
for t in threads:
t.join()
print("Exiting Main Thread")
运行结果:
5、Queue模块
Python的Queue模块主要提供同步的,线程安全的队列类,包括FIFO(先进先出)队列Queue、LIFO(后进先出)队列LifoQueue和优先级队列,这些队列实现锁原语,能够在多线程中直接使用,可以使用队列来实现线程之间同步。
下面一个示例来实现一个先进先出的示例:
import queue
import threading
import time
exitFlag = 0
class myThread(threading.Thread):
def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
# 把要执行的代码写到run函数里面,线程在创建之后直接运行run函数
def run(self):
print("starting" + self.name)
process_data(self.name, self.q)
print("Exiting"+self.name)
def process_data(threadName,q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
data = q.get()
queueLock.release()
print("%s processing %s"%(threadName,data))
else:
queueLock.release()
time.sleep(1)
threadList = ["Thread-1","Thread-2","Thread-3"]
nameList = ["one two","three","four","five",]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1
# 创建新线程
for tName in threadList:
thread = myThread(threadID,tName,workQueue)
thread.start()
threads.append(thread)
threadID += 1
# 填充队列
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
# 等待队列清空
while not workQueue.empty():
pass
# 通知线程时候退出
exitFlag = 1
# 等待所有的线程完成
for t in threads:
t.join()
print("Exiting Main Thread")
运行结果:
6、进程池
进程池毫无疑问就是去创建和销毁大量的进程的,手动创建并管理大量的进程是特别复杂和繁琐的,如果创建的进程不是很多,那么Process就可以用.
Pool类可以提供指定数量的进程供用户调用,当有新的请求提交到# 当需要的子进程特别多的时候,就需要进程池了,Pool类可以提供指定数量的进程供用户调用如果有新的请求提交到Pool中时,如果进程池还没有满,那么就会创建一个新的进程来执行请求。
from multiprocessing import Pool
import os
import random
import time
def task(name):
print("Run task %s(%s)..."%(name,os.getpid()))
time.sleep(random()*3)
if __name__ == '__main__':
print("parent process %s"%os.getpid())
p = Pool(5) # 最大进程为5
for i in range(8):
p.apply_async(task,args=(i,)) # 进程池中添加子进程"
print("waiting for all subprocesses done...")
p.close() #关闭Pool,不在接收其他新的任务
p.join()
print('All subprocesses done...')
"""
对于Pool对象调用join()方法等待所有的子进程执行完毕
调用join()之前必须提前调用close()
调用close()之后就不能继续添加新的process了
"""
运行结果:
好久没学习啦,水平有限,大家多多纠正指导!
如果大家觉得敲代码这些比较麻烦,可以直接在我的主页资源里面下载哦!