进程和线程
一、进程
进程是程序的分配资源的最小单元;一个程序可以有多个进程,但只有一个主进程;
二、线程
线程是程序最小的执行单元;一个进程可以有多个线程,但是只有一个主线程;
三、总结
一个程序至少有一个进程和一个线程;
程序的工作方式:
1.单进程单线程;2.单进程多线程;3.多进程多线程;
考虑到实现的复杂性,一般最多只会采用单进程多线程的工作方式;
四、为什么要使用多线程
我们在实际生活中,希望既能一边浏览网页,一边听歌,一边打游戏。这时,如果只开一个进程,为了满足需求,CPU只能快速切换进程,但是在切换进程时会造成大量资源浪费。所以,如果是多核CPU,可以在同时运行多个进程而不用进行进程之间的切换。
然而,在实际中,比如:你在玩游戏的时候,电脑需要一边显示游戏的动态,一边你还得和同伴进行语音或语言进行沟通。这时,如果是单线程的工作方式,将会造成在操作游戏的时候就无法给同伴沟通,在和同伴沟通的时候就无法操作游戏。为了解决该问题,我们可以开启多线程来共享游戏资源,同时进行游戏操作和沟通。
五、实例
场景一:并发依次执行
如上图所示:有两个简单的函数,一个是听音乐一个是打游戏的函数。
如果按照之前的单线程方式,将会是先运行完听音乐的函数再去运行打游戏的函数,最后打印Ending。如下图所示:
一共的运行时间是6秒。并且是只能单一按照顺序依次去执行。而使用多线时,运行时间是3秒,并且是并行执行。
该情况下的多线程运行方式是,先创建线程1,再创建线程2,然后去启动线程1和线程2,并和主线程同时运行。此种情况下,若子线程先于主线程运行完毕,则子线程先关闭后主线程运行完毕关闭;若主线程先于子线程结束,则主线程要等待所有的子线程运行完毕后再关闭。
该部分代码块:
import threading
import time
def music(name):
print(‘%s begin listen music%s‘%(name,time.ctime()))
time.sleep(3)
print(‘%s stop listen music%s‘ % (name, time.ctime()))
def game(name):
print(‘%s begin play game%s‘%(name,time.ctime()))
time.sleep(3)
print(‘%s stop play game%s‘ % (name,time.ctime()))
if __name__ == ‘__main__‘:
# threadl = []
# t1 = threading.Thread(target=music,args=(‘zhang‘,))
# t2 = threading.Thread(target=game,args=(‘zhang‘,))
# t1.start()
# t2.start()
music(‘zhang‘)
game(‘zhang‘)
print(‘Ending now %s‘%time.ctime())
场景二:主线程等待某子线程结束后才能执行(join()函数的用法)
例如:在实际中,需要子线程在插入数据,主线程需要等待数据插入结束后才能进行查询验证操作(测试验证数据)
该部分代码块为:
import threading
import time
def music(name):
print(‘%s begin listen music%s‘%(name,time.ctime()))
time.sleep(5)
print(‘%s stop listen music%s‘ % (name, time.ctime()))
def game(name):
print(‘%s begin play game%s‘%(name,time.ctime()))
time.sleep(3)
print(‘%s stop play game%s‘ % (name,time.ctime()))
if __name__ == ‘__main__‘:
threadl = [] #线程列表,用例存放线程
#产生线程的实例
t1 = threading.Thread(target=music,args=(‘zhang‘,)) #target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式;
t2 = threading.Thread(target=game,args=(‘zhang‘,))
threadl.append(t1)
threadl.append(t2)
#循环列表,依次执行各个子线程
for x in threadl:
x.start()
#将最后一个子线程阻塞主线程,只有当该子线程完成后主线程才能往下执行
x.join()
print(‘Ending now %s‘%time.ctime())
该部分代码块为:
import threading
import time
def music(name):
print(‘%s begin listen music%s‘%(name,time.ctime()))
time.sleep(2)
print(‘%s stop listen music%s‘ % (name, time.ctime()))
def game(name):
print(‘%s begin play game%s‘%(name,time.ctime()))
time.sleep(5)
print(‘%s stop play game%s‘ % (name,time.ctime()))
if __name__ == ‘__main__‘:
threadl = [] #线程列表,用例存放线程
#产生线程的实例
t1 = threading.Thread(target=music,args=(‘zhang‘,)) #target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式;
t2 = threading.Thread(target=game,args=(‘zhang‘,))
threadl.append(t1)
threadl.append(t2)
#循环列表,依次执行各个子线程
for x in threadl:
x.start()
#将子线程t1阻塞主线程,只有当该子线程完成后主线程才能往下执行
t1.join()
print(‘Ending now %s‘%time.ctime())
六、线程守护(setDaemon()函数)
前面不管是不是用到了join()函数,主线程最后总是要得所有的子线程执行完成后且自己执行完才能关闭(以子线程为主来结束主线程)。下面,我们讲述一种以主线程为主的方法来结束主线程。
图1:无线程守护
图2:t2线程守护
该部分代码块为:
import threading
import time
def music(name):
print(‘%s begin listen music%s‘%(name,time.ctime()))
time.sleep(2)
print(‘%s stop listen music%s‘ % (name, time.ctime()))
def game(name):
print(‘%s begin play game%s‘%(name,time.ctime()))
time.sleep(5)
print(‘%s stop play game%s‘ % (name,time.ctime()))
if __name__ == ‘__main__‘:
threadl = [] #线程列表,用例存放线程
#产生线程的实例
t1 = threading.Thread(target=music,args=(‘zhang‘,)) #target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式;
t2 = threading.Thread(target=game,args=(‘zhang‘,))
threadl.append(t1)
threadl.append(t2)
#循环列表,依次执行各个子线程
t2.setDaemon(True) #t2线程守护
for x in threadl:
x.start()
#将子线程t1阻塞主线程,只有当该子线程完成后主线程才能往下执行
print(‘Ending now %s‘%time.ctime())
所谓’线程守护’,就是主线程不管该线程的执行情况,只要是其他子线程结束且主线程执行完毕,主线程都会关闭。也就是说:主线程不等待该守护线程的执行完再去关闭。
注意:setDaemon方法必须在start之前且要带一个必填的布尔型参数
七、自定义的方式来产生多线程
该部分代码块为:
import threading
import time
class mythread1(threading.Thread):
‘自定义线程‘
def __init__(self,name):
threading.Thread.__init__(self)
self.name=name
def run(self):
‘定义每个线程要运行的函数,此处为music函数‘
print(‘%s begin listen music, %s‘ % (self.name, time.ctime()))
time.sleep(5)
print(‘%s stop listen music, %s‘ % (self.name, time.ctime()))
class mythread2(threading.Thread):
‘自定义线程‘
def __init__(self,name):
threading.Thread.__init__(self)
self.name=name
def run(self):
‘定义每个线程要运行的函数,此处为game函数‘
print(‘%s begin play game, %s‘ % (self.name, time.ctime()))
time.sleep(2)
print(‘%s stop play game, %s‘ % (self.name, time.ctime()))
if __name__ == ‘__main__‘:
threadl = []
t1 = mythread1(‘zhang‘)
t2 = mythread2(‘zhang‘)
threadl.append(t1)
threadl.append(t2)
for x in threadl:
x.start()
print(‘Ending now %s‘ % time.ctime())
八、Threading的其他常用方法
getName() :获取线程名称
setName():设置线程名称
run():用以表示线程活动的方法(见七中自定义线程的run方法)
rtart():启动线程活动
is_alive():表示线程是否处于活动的状态,结果为布尔值;
threading.active_count():返回正在运行线程的数量
Threading.enumerate():返回正在运行线程的列表
该部分代码块为;
import threading
import time
def music(name):
print(‘%s begin listen music%s‘%(name,time.ctime()))
time.sleep(2)
print(‘%s stop listen music%s‘ % (name, time.ctime()))
def game(name):
print(‘%s begin play game%s‘%(name,time.ctime()))
time.sleep(5)
print(‘%s stop play game%s‘ % (name,time.ctime()))
if __name__ == ‘__main__‘:
threadl = [] #线程列表,用例存放线程
#产生线程的实例
t1 = threading.Thread(target=music,args=(‘zhang‘,)) #target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式;
t2 = threading.Thread(target=game,args=(‘zhang‘,))
threadl.append(t1)
threadl.append(t2)
#循环列表,依次执行各个子线程
t2.setDaemon(True) #t2线程守护,setDaemon方法必须在start之前且要带一个必填的布尔型参数
t1.setName(‘线程1‘) #设置线程的名字
for x in threadl:
print(‘线程为:‘,x.getName()) #获取线程的名字
print(‘线程t1是否活动:‘,t1.is_alive()) #判断线t1是否处于活动状态
x.start()
print(‘正在运行线程的数量为:‘,threading.active_count()) #获取正处于活动状态线程的数量
print(‘正在运行线程的数量为:‘,threading.activeCount) #获取正处于活动状态线程的数量
print(‘正在运行线程的list为:‘,threading.enumerate()) #获取正处于活动状态线程的list
print(‘正在运行线程的list为:‘,threading._enumerate()) #获取正处于活动状态线程的list
#将子线程t1阻塞主线程,只有当该子线程完成后主线程才能往下执行
print(‘正在运行的线程为:‘,threading.current_thread().getName()) #获取当前线程的名字
print(‘Ending now %s‘%time.ctime())
九、进程锁
原文地址:http://blog.51cto.com/10836356/2175009