1.什么是线程?
线程指的是程序的执行线路,相当于一条流水线,包含了程序的具体执行步骤,一条流水线必须属于一个车间,一个车间的工作过程就是一个进程,车间负责把资源整合到一起,是一个资源单位,而车间内至少有一条流水线,也就是说一个进程至少有一个线程。
进程是一个资源单位,线程是CPU的最小执行单位。
线程和进程的关系:进程包含了运行程序需要的所有资源,每一个进程一旦被创建,就默认开启了一条线程,称之为主线程。一个进程可以包含多个线程,而线程依赖进程。
2.什么是多线程?
多线程指的是在一个进程中存在多个线程,多个线程共享该进程的地址空间,相当于一个车间内有多条流水线,都公用一个车间的资源。
注:多进程之间内存地址是相互隔离的,多线程之间的资源是共享的。
3.为什么使用多线程?
因为多进程对操作系统的资源耗费非常高,每开一个进程都要申请内存空间,而开线程,就相当于在一个车间内造一条流水线,无需申请空间,对操作系统的资源耗费比较小。多线程可以使CPU在一个进程内进行切换,从而提到CPU的占用率,从而提高程序的效率。
应用场景:当遇到I/O操作时,就可以使用多线程。
进程和线程的区别:
1.进程对于操作系统的资源耗费非常高,而线程相反(比进程低10-100倍)。
2.在同一个进程中,多个线程之间资源共享的;多个进程之间,内存是相互隔离的,即资源不共享。
4.开启线程的两种方式
1.实例化Thread类的对象
from threading import Thread def task(): print('子线程。。。') t = Thread(target=task) t.start() print('主') # 子线程。。。 # 由于开启线程的速度非常快,所以有可能的情况就是子线程一经开启,就立马执行其中代码 # 主
2.继承Thread类,覆盖run方法
class MyThread(Thread): def run(self): print("子线程 running....") MyThread().start() print("over2")
5.多进程和多线程对比
1.开启速度
from threading import Thread import time def task(): pass start = time.time() l = [] for i in range(100): t = Thread(target=task) l.append(t) t.start() print(time.time()-start) for t in l: t.join() print('主') # 0.015770673751831055 # 主
from multiprocessing import Process import time def task(): pass l = [] if __name__ == '__main__': start = time.time() for i in range(100): p = Process(target=task) l.append(p) p.start() print(time.time()-start) for p in l: p.join() print('主') # 3.595005750656128 # 主
2.PID
from multiprocessing import Process import time import os def task1(): print(os.getpid()) # 9528 def task2(): print(os.getpid()) # 11704 if __name__ == '__main__': p1 = Process(target=task1) p1.start() p2 = Process(target=task2) p2.start()
from threading import Thread import time import os def task1(): print(os.getpid()) # 7560 def task2(): print(os.getpid()) # 7560 if __name__ == '__main__': t1 = Thread(target=task1) t1.start() t2 = Thread(target=task2) t2.start()
3.数据共享
from threading import Thread x = 100 def task(): global x x = 0 l = [] for i in range(100): t = Thread(target=task) t.start() l.append(t) for t in l: t.join() print(x) print('over') # 0 # over
from multiprocessing import Process x = 100 def task(): global x x = 0 l = [] if __name__ == '__main__': for i in range(100): t = Process(target=task) t.start() l.append(t) for t in l: t.join() print(x) print('over') # 100 # over
6.线程相关的其他方法
Thread实例对象的方法 # isAlive(): 返回线程是否活动的。 # getName(): 返回线程名。 # setName(): 设置线程名。 threading模块提供的一些方法: # threading.currentThread(): 返回当前的线程变量。 # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
from threading import Thread import threading from multiprocessing import Process import os def work(): import time time.sleep(3) print(threading.current_thread().getName()) if __name__ == '__main__': #在主进程下开启线程 t=Thread(target=work) t.start() print(threading.current_thread().getName()) print(threading.current_thread()) #主线程 print(threading.enumerate()) #连同主线程在内有两个运行的线程 print(threading.active_count()) print('主线程/主进程') ''' 打印结果: MainThread <_MainThread(MainThread, started 140735268892672)> [<_MainThread(MainThread, started 140735268892672)>, <Thread(Thread-1, started 123145307557888)>] 主线程/主进程 Thread-1 '''
7.守护线程
守护线程会在所有非守护线程结束后结束。主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时进行回收),因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
from threading import Thread import time def task(): print('子线程 run....') time.sleep(0.1) print('子线程 over...') t = Thread(target=task) t.daemon = True # 必须在start前 t.start() print('主线程 over...') # 子线程 run.... # 主线程 over...
from threading import Thread import time def task1(): print('子线程1 run....') time.sleep(0.1) print('子线程1 over...') def task2(): print('子线程2 run....') # time.sleep(1) print('子线程2 over...') t1 = Thread(target=task1) t2 = Thread(target=task2) t1.daemon = True # 必须在start前 t1.start() t2.start() print('主线程 over...') # 子线程1 run.... # 子线程2 run.... # 子线程2 over... # 主线程 over...
8.线程互斥锁
当多个线程需要同时修改同一份数据时,可能会造成数据错乱,所以这时必须加锁。
from threading import Thread,Lock import time lock = Lock() x = 100 def task(): lock.acquire() global x t = x - 1 time.sleep(0.01) x = t lock.release() l = [] for i in range(100): t = Thread(target=task) t.start() l.append(t) for t in l: t.join() print(x) print('over') # 0 # over
信号量:也是一种锁,其特点是可以设置一个数据可以被几个线程(进程)共享,即可以让这个数据在同一时间能被多个线程使用。它的应用场景是可以限制一个数据被同时访问的次数,保证程序正常运行。
from threading import Thread,Semaphore,current_thread import time sem = Semaphore(4) # 其中的参数可以设置有几个线程可以同时共享数据 def task(): sem.acquire() print('%s run...' % current_thread()) time.sleep(2) sem.release() for i in range(10): t = Thread(target=task) t.start()
线程互斥锁与信号量图解
http://url.cn/5DMsS9r