Python--多线程

多线程类似于同时执行多个不同程序,多线程运行有如下优点:

1、使用线程可以把占据长时间的程序中的任务放到后台去处理。

2、用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度程序的运行速度可能加快

3、在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

4、线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。

指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。

线程可以被抢占(中断)。在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) – 这就是线程的退让。

Python中使用线程有两种方式:函数或者用类来包装线程对象。

下面我以两个简单的示例来解释这两种方式:

模拟用多线程下载文件,用的是函数的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from random import randint
from threading import Thread
from time import time, sleep


def download(filename):
print('开始下载%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下载完成! 用时%d秒' % (filename, time_to_download))


def main():
start = time() # 开始的时间点
t1 = Thread(target=download, args=('A文件',)) # 注意字符串后面的逗号,表示传入的是元组
t1.start() # 启动下载A文件的线程
t2 = Thread(target=download, args=('B文件',))
t2.start()
t1.join() # 等待执行结束
t2.join() # 等待执行结束
end = time() # 结束的时间点
print('总共耗费了%.5f秒' % (end - start))


if __name__ == '__main__':
main()

用多线程写的赛车动画,五个线程控制五辆由色块表示的小车移动,这样小车可以同时移动,而不是一辆一辆依次移动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import pygame
from random import uniform, randint
from threading import Thread


class Car(object):

def __init__(self, x, y):
self._color = [randint(0, 255), randint(0, 255), randint(0, 255)]
self._x = x
self._y = y

@property
def x(self):
return self._x

def move(self):
self._x += uniform(0.5, 3)

def head(self):
return self._x + 20

def draw(self, screen):
pygame.draw.rect(screen, self._color, (self._x, self._y, 20, 20), 0)

def run(self, screen):
self.move()
self.draw(screen)


class Mythread(Thread):
def __init__(self, car, screen):
super().__init__()
self._car = car
self._screen = screen

def run(self):
Car.move(self._car)
Car.draw(self._car, self._screen)


def main():
pygame.init()

screen = pygame.display.set_mode([600, 500])
pygame.display.set_caption('赛车游戏')
screen.fill([255, 255, 255])
pygame.draw.line(screen, [0, 0, 0], (37, 0), (37, 500), 5)
pygame.draw.line(screen, [255, 0, 0], (580, 0), (580, 500), 5)
cars = []
for i in range(5):
car = Car(20, 50+100*i)
cars.append(car)
for car in cars:
car.draw(screen)
pygame.display.flip()
running = True
gameover = False

def game_over(c1):
nonlocal gameover
if c1.head() > 580:
gameover = True

def refresh():
screen.fill((255, 255, 255))
pygame.draw.line(screen, [0, 0, 0], (37, 0), (37, 500), 5)
pygame.draw.line(screen, [255, 0, 0], (580, 0), (580, 500), 5)
for _ in cars:
Mythread(_, screen).start()
pygame.display.flip()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
while not gameover:
for car in cars:
game_over(car)
refresh()
pygame.display.flip()

pygame.quit()


if __name__ == '__main__':
main()