线程,多线程:
-
线程的理论知识:
-
什么是线程:
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位
-
进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
-
在内存中开启一个进程空间,然后将主进程的所有的资源数据复制一份,然后去调用线程去执行代码。
-
进程是资源单位,线程是执行单位
-
-
线程vs进程:
-
启动进程的开销非常大,比开启线程的开销大很多
-
开启线程的速度非常快,
-
线程与线程之间可以共享数据,进程与进程之间需要借助队列等方法实现通信。
from threading import Thread x = 3 def task(): global x x = 10 if __name__ == '__main__': t1 = Thread(target=task) t1.start() t1.join() print(x) # x 的值是10,所以在线程中,是可以做到数据共享的同一进程内的资源数据对于这个进程的多个线程来说是共享的.
-
-
线程的应用:
并发:一个cup看起来像是同时执行多个任务
-
开启线程的两种方式:
from threading import Thread # 导入线程的模块 import time import random def task(name): print(f'{name} is running') time.sleep(random.random()) print(f'{name} is gone') if __name__ == '__main__': t = Thread(target=task,args=('周道容',)) t.start() # 开启线程 print('----主')from threading import Thread import time import random class MyThread(Thread): # 定义一个类,继承Thread类,执行其中的一些方法 def __init__(self,name): super().__init__() self.name = name def run(self): # 必须要有run方法 print(f'{self.name} is running') time.sleep(random.random()) print(f'{self.name} is gone') if __name__ == '__main__': t = MyThread('周道容') t.start() print('----主')其本质是重构Thread类中的run方法
-
线程的相关其他方法:
isAlive() ----- 判断线程是否活着
getName() ----- 获取线程名
setName(线程名字) ------ 添加线程名
name ----- 获取线程名
threading 方法:
currentThread() ----- 获取当前线程的对象(需要导入currentThread包)
import threading import time def run(arg): print(f'running sub thread:{threading.currentThread()}') threading.currentThread().name = 'task1' print(f'sub1 Thread...{threading.currentThread().getName()}') print(f'sub2 Thread...{threading.currentThread().name}') time.sleep(2) if __name__ == '__main__': t1 = threading.Thread(target=run,args=('t1',)) t1.start() print(f'sub1 Thread...{threading.currentThread().getName()}') print(f'sub2 Thread...{threading.currentThread().name}') ''' running sub thread:<Thread(Thread-1, started 11788)> sub1 Thread...MainThread sub1 Thread...task1 sub2 Thread...MainThread sub2 Thread...task1 '''enumerate() -------- 返回一个列表,包含所有的线程对象 (需要导入enumerate包)
activeCount()------ 统计正在运行的线程数
import threading import time def run(n): print(f'task{n}') time.sleep(1) for i in range(3): t = threading.Thread(target=run,args=(i,)) t.start() time.sleep(1) print(threading.activeCount()) -
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=('小猿',)) t3 = Thread(target=task,args=('小猿',)) t1.start() t1.join() t2.start() t2.join() t3.start() t3.join() print(time.time()-start_time)守护线程:
from threading import Thread import time def task(): print(123) time.sleep(2) print(789) if __name__ == '__main__': t = Thread(target=task) t.daemon = True t.start() print(456) # 线程的开启速度非常快,所以会先执行task,输出123, # 结果: 123 456注意:
from threading import Thread import time def foo(): print(123) time.sleep(3) print('end123') def bar(): print(456) time.sleep(3) print('end456') t1=Thread(target=foo) t2=Thread(target=foo) t1.daemon = True t1.start() t2.start() print('main-----') #结果: 123 123 main----- end123 end123 -
互斥锁,锁
由于线程之间都是随机调度的,当它们同时修改一个数据时,就是产生脏数据,所以就会出现锁,使其在同一时间内只能有一个线程对同一个数据进行操作。
线程锁:
import threading def run(): global num num += 1 # 会产生数据不安全 num = 0 t_obj = [] for i in range(50): t = threading.Thread(target=run) t.start() t_obj.append(t) for i in t_obj: i.join() # 让其每次执行都按顺序随机 print(num)
互斥锁:
from threading import Thread
from threading import Lock
x = 100
def task(lock):
lock.acquire()
global x
tem = x
x = tem - 1
lock.release()
if __name__ == '__main__':
mutex = Lock()
for i in range(100):
t = Thread(target=task,args=(mutex,))
t .start()
print(x)
with:线程中锁的自动获取和释放等。
所以上边的代码可以写成:
from threading import Thread,Lock
x = 100
def task(lock):
with lock:
global x
tem = x
x = tem - 1
mutex = Lock()
for i in range(100):
t = Thread(target=task,args=(mutex,))
t.start()
print(x)
来源:https://blog.csdn.net/adrian_boy/article/details/100046420