进程和线程的由来
进程
为了提高批处理操作系统的效率,人们发明了进程,用进程来对应一个程序,每个进程来对应一定的内存地址空间,并且只能使用它自己的内存空间,各个进程之间互不干扰。进程同时也保存了程序每个时刻的运行状态,为进程切换提供了可能。当进程暂停时,它会保存当前进程的状态(进程标识,进程使用的资源等),在下一次切换回来时根据之前保存的状态进行恢复,接着继续执行。进程让操作体统的并发成为了可能。虽然并发从宏观上看有多个任务在执行,但在事实上,对于单核CPU来说,任意具体时刻都只有一个任务在占用CPU资源。
线程
出现了进程之后,操作系统的性能得到了大大的提升。虽然进程的出现解决了操作系统的并发问题,但是人们不满足,逐渐对实时性有了要求。因为一个进程在一个时间段内只能做一个事情,如果一个进程有多个子任务时,只能逐个得执行这些子任务,很影响效率。为了处理这种情况,人们发明了线程,让一个线程执行一个子任务,这样一个进程就包含了多个线程,每个线程负责一个单独的子任务。
进程和线程的区别
最大的区别是:是否单独占有内存地址空间
(1)进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元
(2)同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进行至少包括一个线程。
(3)进程的创建调用fork或者vfork,而线程的创建调用pthread_create,进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束
(4)线程是轻两级的进程,它的创建和销毁所需要的时间比进程小很多,所有操作系统中的执行功能都是创建线程去完成的
(5)线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源
(6)线程有自己的私有属性TCB,线程id,寄存器、硬件上下文,而进程也有自己的私有属性进程控制块PCB,这些私有属性是不被共享的,用来标示一个进程或一个线程的标志。(参考:https://blog.csdn.net/zhou753099943/article/details/51771220)
python中实现多进程和多线程
import time
from multiprocessing import Process
def output():
count = 0
while count < 30:
print('a', end=' ', flush=True)
count += 1
time.sleep(0.2)
print('%d个a' % count)
def main():
Process(target=output).start()
count = 0
while count < 30:
print('b', end=' ',flush=True)
count += 1
time.sleep(0.2)
print('%d个b' % count)
if __name__ == '__main__':
main()
创建线程的方式:1、直接创建Thread对象并通过target参数指定线程启动后要执行的任务。2、继承Thread自定义线程,通过重写run方法指定线程启动后执行的任务。
from threading import Thread
#count是全局变量,只有一个,inner_count每个线程有一个
count = 0
def output(string):
global count
inner_count = 0
while count < 100:
print(string, end='', flush = True)
count += 1
inner_count += 1
print('
%s打印了%d次
' % (string, inner_count))
def main():
#output不能加括号
#daemon是守护线程,不值得保留的线程,其他线程如果都结束了,守护线程也自动结束
Thread(target=output, args=('ping'), daemon=True).start()
Thread(target=output, args=('pong',),daemon=True).start()
if __name__ == '__main__':
main()
无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁 需要强调的是:运行完毕并非终止运行
#1.对主进程来说,运行完毕指的是主进程代码运行完毕.主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束。
#2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕。主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
多线程在游戏中的应用:赛车
from random import randint
from threading import Thread
from time import sleep
import pygame
class Color(object):
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (242, 242, 242)
@staticmethod
def random_color():
r = randint(0, 255)
g = randint(0, 255)
b = randint(0, 255)
return r, g, b
class Car(object):
def __init__(self, x, y, color):
self._x = x
self._y = y
self._color = color
def move(self):
if self._x + 60 <= 950:
self._x += randint(1, 10)
def draw(self, screen):
pygame.draw.rect(screen, self._color, (self._x, self._y, 60, 30), 0)
def main():
class BackgroundTask(Thread):
def run(self):
while True:
screen.fill(Color.GRAY)
pygame.draw.line(screen,Color.BLACK,(130, 0),(130, 600),4)
pygame.draw.line(screen,Color.BLACK,(950, 0),(950, 600),4)
for car in cars:
car.draw(screen)
pygame.display.flip()
sleep(0.05)
for car in cars:
car.move()
cars = []
for index in range(5):
temp = Car(70 , 50+ 120 * index, Color.random_color())
cars.append(temp)
car1 = Car(70, 50, Color.random_color())
pygame.init()
screen = pygame.display.set_mode((1000, 600))
BackgroundTask(daemon=True).start()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
if __name__ == '__main__':
main()
推荐:更多关于进程和线程的知识可以查看骆昊老师博客: https://blog.csdn.net/jackfrued/article/details/79717727