进程和线程
进程:进程是程序的一次执行,每个进程都有自己的地址空间、内存、数据栈,以及其他记录其运行轨迹的辅助数据。操作系统管理在其上面运行的所有进程,并为这些进程公平的分配时间。
线程:(轻量型进程)所有的线程都运行在同一个进程中,共享相同的运行环境。
单线程和多线程
单线程:
单线程中处理器要处理多个任务时,必须对这些任务安排优先级,先执行谁后执行谁。
onethread.py
from time import *
def movie(name,loop): #线程1
for i in range(loop):
print("我在电影:%s,现在是:%s"%(name,ctime()))
sleep(2)
def music(name,loop): #线程2
for i in range(loop):
print("我在听音乐:%s,现在是:%s"%(name,ctime()))
sleep(2)
if __name__ == "__main__":
movie("爱我别跑",2)
music("流星雨",3)
多线程:
Python通过thread库和threading库提供对线程的支持。thread库和threading库的区别:
- thread库提供了低级别的、原始的线程以及一个简单的锁;
- threading库是基于Java的线程模式设计,锁lock和条件变量condition在Java中是对象的基本行为(每一个对象都自带了锁和条件变量),而在Python中则是独立的对象;
- thread库不支持守护线程,也就是当主线程退出时,所有的子线程都会强行退出,不管其工不工作;
- threading库支持守护线程,主线程退出后仍在工作的子线程不会退出。
所以请使用threading库。
threads1.py
from time import *
import threading
#线程1
def music(name,loop):
for i in range(loop):
print("我在听:%s,现在是%s"%(name,ctime()))
sleep(2)
#线程2
def movie(name,loop):
for i in range(loop):
print("我在看:%s,现在是%s"%(name,ctime()))
sleep(2)
#创建空数组用来装载线程1,2
threads =[]
#创建线程t1,并添加到线程组threads
t1 = threading.Thread(target=music,args=("后来",2))
threads.append(t1)
#创建线程t2,并添加到线程组threads
t2 = threading.Thread(target=movie,args=("超人3",2))
threads.append(t2)
if __name__ == "__main__":
#启动线程
for i in threads:
i.start() #开始线程活动
#守护线程
for i in threads:
i.join() #等待线程终止
print("运行结束了。")
可以看到两个线程并行工作!!!!!
threading.Thread(target=,args=(),name=None,group=None,kwargs={})
- target表示调用的对象;
- args表示调用对象的位置参数元组;
- kwargs表示调用对象的字典;
- name表示该线程名;
- group实际上不使用。
上面的例子中可发现线程的创建有些麻烦,每创建一个线程需要创建一个t(t1,t2,t3...)当创建的线程很多的时候这样极其不方便,
下面是优化的多线程:
threads2.py
from time import sleep,ctime
import threading
def super_player(file_,time):
for i in range(2):
print('开始播放:%s!%s'%(file_,ctime()))
sleep(time)
#播放文件和播放时长
dicts ={'真爱.mp3':2,'阿凡达.mp4':5,'我和你':4}
#创建线程空数组,用于存放线程
threads =[]
files = range(len(dicts))
#创建线程(遍历字典)并添加到线程数组内
for file_,time in dicts.items():
t = threading.Thread (target=super_player,args=(file_,time))
threads.append(t) #
if __name__ =='__main__':
#启动线程
for i in files:
threads[i].start()
#守护线程
for i in files:
threads[i].join()
print('end all:%s'%ctime())
自定义线程类
除了使用python提供的线程外,我们可以根据自己的需求定义自己的线程类:
mythreads.py
import threading
from time import sleep,ctime
#创建线程类
class MyThread(threading.Thread):
def __init__(self,func,args,name=''):
threading.Thread.__init__(self) #super().__init__()
self.func = func
self.args = args
self.name = name
def run(self):
self.func(*self.args) #python2不支持这种方式
def super_play(file_,time):
for i in range(2):
print("开始播放:%s!%s"%(file_,ctime()))
sleep(time)
dicts ={"真爱.mp3":3,"阿凡达.mp4":5,"我和你.mp3":5}
threads =[]
files = range(len(dicts))
for file_,time in dicts.items():
t = MyThread(super_play,(file_,time),super_play.__name__)
threads.append(t)
if __name__=='__main__':
#启动线程
for i in files:
threads[i].start()
for i in files:
threads[i].join()
print('all end:%s'%ctime())
多进程技术
多进程使用multiprocessing模块,与多线程的threading模块用法类似。
多进程的优势:
multiprocessing提供了本地和远程的并发性,有效地通过全局解释锁(GIL)来使用进程而不是线程。由于GIL的存在,在CPU密集型的程序当中,使用多线程并不能有效地利用多核CPU的优势,因为一个解析器在同一时刻只会有一个线程在执行。所以muitiprocessing模块可以充分利用硬件的多处理器来进行工作。
多进程使用的multiprocessing模块使用Process对象来创建一个进程,Process对象使用和多线程的Thread对象使用方法相同,
- start() 开启进程活动;
- run() 运行进程
- join() 等待进程的终止
multiprocessing.Process(target=,args=(),name=,kwargs={},group=None)
- target表示调用的对象;
- args表示调用对象的位置参数,元组;
- kwargs表示调用对象的字典,字典{};
- name进程的名字;
- group实际上不使用。
process.py
from time import *
import multiprocessing
def surper_player(file_,time):
for i in range(2):
print('start playing:%s.%s'%(file_,ctime()))
sleep(time)
lists ={'loving.mp3':3,'makeloving.mp4':5}
threads =[]
files =range(len(lists))
#创建进程
for file_,time in lists.items():
t =multiprocessing.Process(target=surper_player,args=(file_,time))
threads.append(t)
if __name__ =="__main__":
#启动进程
for t in files:
threads[t].start()
for t in files:
threads[t].join()
运行结果和多线程几乎一样。。。
Pipe和Queue
IPC进程间通信
pipe.py
import multiprocessing
from time import ctime
def proc1(pipe):
pipe.send('hello') #进程从pipe一端输入对象
print('proc1 rec:',pipe.recv(),ctime()) #被pipe另一端的进程接收
def proc2(pipe):
print('proc2 rec:',pipe.recv(),ctime()) #被pipe一段的进程接收
pipe.send('hello,too.') #进程从pipe另一端输入对象
#这里的pipe双向的,pipe对象建立的时候,返回一个含有两个元素的表,每个元素代表pipe的一端,对pipe的某一端调用send()方法来传送对象,在另一端使用recv()接收
if __name__ =="__main__":
multiprocessing.freeze_support()
pipe = multiprocessing.Pipe()
p1 = multiprocessing.Process(target=proc1,args=(pipe[0],))
p2 = multiprocessing.Process(target=proc2,args=(pipe[1],))
p1.start()
p2.start()
p1.join()
p2.join()
queque.py
import multiprocessing,os
from time import *
def inputQ(queue):
info = str(os.getpid()) + 'put():' + str(ctime())
queue.put(info)
def outputQ(queue,lock):
info = queue.get()
lock.acquire()
print((str(os.getpid()) + 'get():' + info))
lock.release()
if __name__ =="__main__":
record1 = []
record2 = []
lock = multiprocessing.Lock()
queue = multiprocessing.Queue(3)
for i in range(10):
process = multiprocessing.Process(target=inputQ,args=(queue,))
process.start()
record1.append(process)
for i in range(10):
process =multiprocessing.Process(target=outputQ,args=(queue,lock))
process.start()
record2.append(process)
for i in record1 :
i.join()
queue.close()
for i in record2:
i.join()