目录
- 1.什么是线程
- 2.线程与进程的区别
- 3.为何要用多线程
- 4.开启线程的两种方式
- 5.多进程与多线程开启的速度区别
- 6.进程线程
- 7.同一进程内线程是共享数据的
- 8.线程的其他方法
- 9. join 与 守护线程
- 10. 互斥锁
1.什么是线程
# 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
# 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程
# 车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线
# 流水线的工作需要电源,电源就相当于cpu
进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源
2.线程与进程的区别
1.线程共享创建它的进程的地址空间;进程有自己的地址空间。
2.线程可以直接访问其进程的数据段;进程有自己的父进程数据段副本。
3.线程可以直接与其进程的其他线程通信;进程必须使用进程间通信与兄弟进程通信。
4.新线程很容易创建;新进程需要父进程的重复。
5.线程可以对同一进程的线程进行相当大的控制;进程只能对子进程进行控制。
6.对主线程的更改(取消、优先级更改等)可能会影响进程的其他线程的行为;对父进程的更改不会影响子进程。
3.为何要用多线程
多线程指的是,在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程。详细的讲分为4点:
1. 多线程共享一个进程的地址空
2. 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用
3. 若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。
4. 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)
4.开启线程的两种方式
4.1第一种方式
from threading import Thread
import time
def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone')
if __name__ == '__main__':
p = Tread(target = task,args = ('小冯',))
p.start()
print('===主线程') # 线程是没有主次之分的
4.2第二种
from threading import Thread
import time
class MyThread(Thread):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
print(f'{self.name} is running')
time.sleep(1)
print(f'{self.name} is gone')
if __name__ == '__main__':
p = MyThread('小冯')
p.start()
print('主===>')
5.多进程与多线程开启的速度区别
5.1多进程
from multiprocessing import Prcess
import os
def task():
print('子进程')
if __name__ == '__main__':
p = Process(target = task)
p.start()
print('主===>')
5.2多线程
from threading import Thread
import time
def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone')
if __name__ == '__main__':
p = Tread(target = task,args = ('小冯',))
p.start()
print('===主线程') # 线程是没有主次之分的
6.进程线程
# 进程
from multiprocessing import Process
import time
import os
def task(name):
print(f'子进程: {os.getpid()}')
print(f'主进程: {os.getppid()}')
if __name__ == '__main__':
p1 = Process(target=task,args=('常鑫',)) # 创建一个进程对象
p2 = Process(target=task,args=('常鑫',)) # 创建一个进程对象
p1.start()
p2.start()
print(f'==主{os.getpid()}')
# 线程:
from threading import Thread
import os
def task():
print(os.getpid())
if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task)
t1.start()
t2.start()
print(f'===主线程{os.getpid()}') # os.getpid()只是获取当前的进程号
7.同一进程内线程是共享数据的
from threading import Thread
import os
x = 3
def task():
global x
x = 100
if __name__ == '__main__':
t1 = Thread(target=task)
t1.start()
t1.join()
print(f'===主线程{x}')
# 同一进程内的资源数据对于这个进程的多个线程来说是共享的.
8.线程的其他方法
from threading import Thread,current_thread,enumerare,activeCount
import os
import time
x = 3
def task():
# print(currentThread())
time.sleep(1)
print('666')
print(123)
if __name__ == '__main__':
t1 = Thread(target=task,name='线程1')
t2 = Thread(target=task,name='线程2')
# name 设置线程名
t1.start()
t2.start()
# time.sleep(2)
# print(t1.isAlive()) # 判断线程是否活着
# print(t1.getName()) # 获取线程名
# t1.setName('子线程-1')
# print(t1.name) # 获取线程名 ***
# threading方法
# print(currentThread()) # 获取当前线程的对象
# print(enumerate()) # 返回一个列表,包含所有的线程对象
print(activeCount()) # ***
print(f'===主线程{os.getpid()}')
9. join 与 守护线程
# join: 阻塞 告知主线程要等待我子线程执行完毕之后再执行主线程
from threading import Thread
import time
def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone')
if __name__ == '__main__':
start_time = time.time()
t1 = Thread(target = task,args = ('小冯',))
t2 = Thread(target = task,args = ('小冯1',))
t3 = Thread(target = task,args = ('小冯2',))
t1.start()
t2.start()
t3.start()
print(f'===主线程{time.time() - start_time}') # 线程是没有主次之分的
# ---------------------------------------------------
# 守护线程
# 回忆一下守护进程
from multiprocessing import Process
import time
def foo():
print(123)
time.sleep(1)
print("end123")
def bar():
print(456)
time.sleep(2)
print("end456")
if __name__ == '__main__':
p1 = Process(target=foo,)
p2 = Process(target=bar,)
p1.daemon = True
p1.start()
p2.start()
print('====主')
# ---------------------------------------------------
# 守护线程
from threading import Thread
import time
def sayhi(name):
print('你滚!')
time.sleep(2)
print('%s say hello' %name)
if __name__ == '__main__':
t = Thread(target=sayhi,args=('egon',))
# t.setDaemon(True) #必须在t.start()之前设置
t.daemon = True
t.start() # 线程的开启速度要跟进程开很多
print('主线程')
# ---------------------------------------------------
from threading import Thread
import time
def foo():
print(123) # 1
time.sleep(1)
print("end123") # 4
def bar():
print(456) # 2
time.sleep(3)
print("end456") # 5
t1=Thread(target=foo)
t2=Thread(target=bar)
t1.daemon=True
t1.start()
t2.start()
print("main-------") # 3
# ---------------------------------------------------
# 主线程什么时候结束???
# 守护线程 等待非守护子线程以及主线程结束之后,结束.
from threading import Thread
import time
def foo():
print(123) # 1
time.sleep(3)
print("end123") # 4
def bar():
print(456) # 2
time.sleep(1)
print("end456") # 5
t1=Thread(target=foo)
t2=Thread(target=bar)
t1.daemon=True
t1.start()
t2.start()
print("main-------") # 3
# ---------------------------------------------------
from threading import Thread
import time
def foo():
print(123)
time.sleep(3)
print("end123")
def bar():
print(456)
time.sleep(1)
print("end456")
t1=Thread(target=foo)
t2=Thread(target=bar)
t1.daemon=True
t1.start()
t2.start()
print("main-------")
10. 互斥锁
from threading import Thread
import time
import random
x = 100
def task():
time.sleep(random.randint(1,2))
global x
temp = x
temp = temp - 1
x = temp
if __name__ == '__main__':
l1 = []
for i in range(100):
t = Thread(target=task)
l1.append(t)
t.start()
for i in l1:
i.join()
print(f'主线程{x}')
# 多个任务公抢一个数据,保证数据的安全的目的,要让其串行
from threading import Thread
from threading import Lock
import time
import random
x = 100
def task(lock):
lock.acquire()
# time.sleep(random.randint(1,2))
global x
temp = x
time.sleep(0.01)
temp = temp - 1
x = temp
lock.release()
if __name__ == '__main__':
mutex = Lock()
l1 = []
for i in range(100):
t = Thread(target=task,args=(mutex,))
l1.append(t)
t.start()
time.sleep(3)
print(f'主线程{x}')