进程
是由若干线程
组成的,一个进程至少有一个线程多任务
可以由多进程
完成,也可以由一个进程内的多线程
完成。- Python的线程是真正的
Posix Thread
,而不是模拟出来的线程。
为什么使用多线程
- 多进程和多线程都可以完
同时
执行多任务的功能- 创建进程的系统开销非常大,是一种
重量级
的多任务方式- 进程间的内存空间是
相互独立
的,数据不能共享
- 线程属性某个进程,创建线程的系统开销比较小,是一种
轻量级
的多任务方式- 线程间
共享
所属进程的内存空间,数据可以共享
threading
模块
Python提供了两个线程模块:
_thread
和threading
_thread
是低级模块threading
是高级模块(推荐使用)
使用threading模块中的Thread类
- 实例演示
import time, threading
def loop(): # 新线程执行的代码
print('thread %s is running...' % threading.current_thread().name)
n = 0
while n < 5:
n = n + 1
print('thread %s >>> %s' % (threading.current_thread().name, n))
time.sleep(1)
print('thread %s ended.' % threading.current_thread().name)
print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)
thread MainThread is running...
thread LoopThread is running...
thread LoopThread >>> 1
thread LoopThread >>> 2
thread LoopThread >>> 3
thread LoopThread >>> 4
thread LoopThread >>> 5
thread LoopThread ended.
thread MainThread ended.
- 任何进程都默认启动一个线程,称为
主线程
,主线程可以启动子线程
current_thread()
函数,返回当前线程名,主线程名为MainThread
- 子线程名在创建时指定,如不指将自动命名为
Thread-1,Thread-2
…
查看线程数量
import threading
from time import sleep,ctime
def sing():
for i in range(3):
print("正在唱歌...%d"%i)
sleep(1)
def dance():
for i in range(3):
print("正在跳舞...%d"%i)
sleep(1)
if __name__ == '__main__':
print('---开始---:%s'%ctime())
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
while True:
length = len(threading.enumerate())
print('当前运行的线程数为:%d'%length)
if length<=1:
break
sleep(0.5)
---开始---:Mon Jan 7 22:49:59 2019
正在唱歌...0
正在跳舞...0
当前运行的线程数为:3
当前运行的线程数为:3
正在跳舞...1
正在唱歌...1
当前运行的线程数为:3
当前运行的线程数为:3
当前运行的线程数为:3
正在唱歌...2
正在跳舞...2
当前运行的线程数为:3
当前运行的线程数为:3
当前运行的线程数为:1
线程的封装
为了体现
封装性
,使用threading
模块时,通常会定义一个子类,让它继承自threading.Thread
类,并重写run
方法
import threading
import time
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
msg = "I'm "+self.name+' @ '+str(i) #name属性中保存当前线程名
print(msg)
if __name__ == '__main__':
t = MyThread()
t.start()
I'm Thread-1 @ 0
I'm Thread-1 @ 1
I'm Thread-1 @ 2
threading.Thread
类中的run
方法,用于定义线程的功能函数,可以在自己的线程类中进行重写
- 当
Thread
类的start
方法执行后,会在线程获得运行资源时调用run
方法- 如果直接调用
run
方法,并不能启多线程,而仅仅是一个单线程的程序
课堂练习
实现多线程版的素数计算
import threading
class MyThread(threading.Thread):
def __init__(self, beg, end): # 通过类的构造方法进行参数据传递
super(MyThread, self).__init__() # 要调用父类的构造方法来进行初始化
self.__beg = beg
self.__end = end
def __isPrime(self, n): # 可以将某些处理函数变为私有方法
for x in range(2, n):
if n % x == 0:
return False
else:
return True
def run(self): # 方法名不能改变,只重写
for n in range(self.__beg, self.__end):
if self.__isPrime(n):
print('%s:%d是素数' % (threading.current_thread().name, n))
if __name__ == '__main__':
t1 = MyThread(3, 1001)
t2 = MyThread(1001, 2001)
t3 = MyThread(2001, 3001)
t1.start()
t2.start()
t3.start()
# t1.run() # 如果直接调用run方法,并不能启多线程,而仅仅是一个单线程的程序
# t2.run()
# t3.run()
- end -