一、进程和线程概论
1.什么是进程?
程序是存储在磁盘中的可执行的数据。
进程可以看作是程序的一次执行,每个进程都有自己的内存空间和数据栈。
进程间只能通讯,而不能直接共享信息。
2.什么是线程?
一个进程中可以有多个线程,一个进程中线程共享运行环境,也就是有相同的内存空间、数据栈等。
比如你启动了一个python项目,允许同时100人访问,你就可以人为在python进程中,同时开了100个线程。
虽然一个进程中的线程共享数据,但是每个线程都拥有自己的栈空间和执行队列。
3.进程和线程的关系?
进程和线程的最大区别在于操作系统对其不同的资源管理方式。
一个程序至少有一个进程,一个进程至少有一个线程。
一个进程的崩溃并不会影响其它进程的运行,但是如果一个线程崩溃掉了,当前进程中的线程都会崩掉,因为共享数据。
从逻辑的角度来讲,多线程的意义在于,在一个应用程序中,有多个执行部分可以同时执行。
但是操作系统并不会把多个线程当作单独的应用来对其调度、管理和资源控制。
多线程共享数据,自然可以极大的提高程序的运行效率。
多线程虽然开销小,但是不利于管理,线程则于其刚好相反,同时健壮性更强。
4.并发与并行
并行:物理上具备同一时刻处理多个任务的能力。
并发:逻辑上具备同一时刻处理多个任务的能力。
虽然说并发可以同时里处理多个任务,但是并不是一定要同时执行。
并行一定发生在多核CPU上,并行是并发设计的理想模式。
单核机器上的并发是通过间隔方式切换执行。
单线程通过协程的方式实现并发,协程是主动切换任务来实现的。
python由于GIL锁的缘故,只能实现并发而不能并行。
二、进程和线程的开启方式
1、进程
方式1:
from multiprocessing import Process import time def task1(num): print("开始执行任务task1") time.sleep(num) print("任务task1执行结束") def task2(num): print("开始执行任务task2") time.sleep(num) print("任务task2执行结束") if __name__ == "__main__": p1 = Process(target=task1,args=(5,)) p2 = Process(target=task2,args=(3,)) p1.start() p2.start() # 执行结果: # 开始执行任务task1 # 开始执行任务task2 # 任务task2执行结束 # 任务task1执行结束
方式2:
from multiprocessing import Process import time class TestProcess(Process): def __init__(self,num): super().__init__() self.num = num def run(self): print("任务task开始执行") time.sleep(self.num) print("任务task执行结束") if __name__ == "__main__": my_process = TestProcess(5) my_process.start()
2.线程
方式1:
from threading import Thread import time def task1(num): print("开始执行任务task1") time.sleep(num) print("任务task1执行结束") def task2(num): print("开始执行任务task2") time.sleep(num) print("任务task2执行结束") if __name__ == "__main__": p1 = Thread(target=task1,args=(5,)) p2 = Thread(target=task2,args=(3,)) p1.start() p2.start()
方式2:
from threading import Thread import time class TestThread(Thread): def __init__(self,num): super().__init__() self.num = num def run(self): print("任务task开始执行") time.sleep(self.num) print("任务task执行结束") if __name__ == "__main__": my_process = TestThread(5) my_process.start()
三、锁
1.进程同步锁
上锁之后,将会串行,不会并发执行。
from multiprocessing import Process,Lock import time def task1(num,lock): lock.acquire() print("开始执行任务task1") time.sleep(num) print("任务task1执行结束") lock.release() def task2(num,lock): lock.acquire() print("开始执行任务task2") time.sleep(num) print("任务task2执行结束") lock.release() if __name__ == "__main__": lock = Lock() p1 = Process(target=task1,args=(5,lock)) p2 = Process(target=task2,args=(3,lock)) p1.start() p2.start()
四、进程池和线程池
1.进程池
from concurrent.futures import ProcessPoolExecutor import os,random,time def func(name): print("%s吃了又一碗饭:%s" %(name,os.getpid())) time.sleep(random.randint(1, 3)) if __name__ == "__main__": p = ProcessPoolExecutor(3) #创建一个进程池,里面容纳3个进程 for i in range(7): obj = p.submit(func,'科比%i'%i) p.shutdown(wait=True) #类似与join,并且可以关门,以防在等的过程中又提交新的任务 print("主进程") #执行结果: 科比0吃了又一碗饭:13980 科比1吃了又一碗饭:9636 科比2吃了又一碗饭:12660 科比3吃了又一碗饭:13980 科比4吃了又一碗饭:12660 科比5吃了又一碗饭:9636 科比6吃了又一碗饭:13980 主进程
2.线程池
from threading import Thread,current_thread from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import time,os def task(n): print('%s is running'% current_thread().getName()) time.sleep(3) return n**2 if __name__ =="__main__": t = ThreadPoolExecutor(3) #默认是CPU的核数*5 objs = [] for i in range(7): obj = t.submit(task,i) objs.append(obj) t.shutdown(wait=True) #异步,最终打印结果 for obj in objs: print(obj.result()) print("主",current_thread().getName()) 执行结果: ThreadPoolExecutor-0_0 is running ThreadPoolExecutor-0_1 is running ThreadPoolExecutor-0_2 is running ThreadPoolExecutor-0_2 is running ThreadPoolExecutor-0_1 is running ThreadPoolExecutor-0_0 is running 0 1 4 ThreadPoolExecutor-0_1 is running 9 16 25 36 主 MainThread
五 、守护进程和守护线程
无论是进程还是线程,当主进程结束的时候,守护进程也会随之结束。
from multiprocessing import Process import os,time,random def task(): print('%s is running '%os.getpid()) time.sleep(2) print('%s is done' % os.getppid()) if __name__ == "__main__": p = Process(target=task) p.daemon = True #1.必须在进程开启之前 2.不能再开启子进程 p.start() print("主")