多线程:

多线程的作用 :也是用于提高程序的效率


多进程:
    1.核心是多道技术 (把内存分成 几块)
    2.通过 本质上就是切换 加 保存状态
    3. 当程序 IO 操作较多 可以提高程序效率

多线程
什么是多线程
       程序的执行线路
       相当于与一条流水线,其包含了程序的具体执行步骤
       如果我们把操作系统比喻为一个工厂,进程就是车间,线程就是流水线


线程和进程的关系
       进程中包含了运行该程序需要的所有资源
       * 进程是一个资源单位,线程是CPU的最小执行单位*
       每一个进程一旦被创建,就默认开启了一条线程,称之为主线程
       一个进程可以包含多个线程
       进程包含线程 而 线程依赖进程


为啥使用线程
      是为了提高程序的使用效率
      为何不用多进程提高效率?  是因为进程对操作系统的资源耗费非常高

线程是如何提高效率 的?(多线程提高效率的原理)
       默认情况下 每个程序都有且只有一个主线程序,执行代码时如果遇到了io 操作系统会立即切换到其他应用程序,这就降低了当前应用程序的效率
     对于CPU而言 只要线程可以被执行 所以CPU切换时在不同线程之间进行切换 ,开启多线程如何提高效率?假设 只有两个线程,每个线程都被切换到的概率是二分之一,如果左边的应用程序开启三条子线程,对于左边的应用程序被切换到的概率为三分之二
        多线程可以使用CPU在一个进程内切换,从而提高CPU的占用率
 
如何使用
      两种开启线程的方式
     1.实例化 Thread类
     2.继承 Threa 类  覆盖run 方法

什么情况下因该开启多线程
       当程序中遇到 IO 的时候
       当程序中纯计算任务时 也无法提高效率


进程和线程的区别
  1 进程对于操作系统的资源耗费非常高,而线程相反非常低(比进程低10-100倍)
  2.在同一个进程中,多个线程之间资源是共享的

#开启线程的第一种方式
from threading import Thread
#from multiprocessing import Process (对比进程)

def task():
      print ("thread running)

t1 = Thread (target = task)
t1 . start()
print ("over")

#第二种方式

class MyThread (thread):
      def run(self):
             print ("子线程 running......")
MyThread().start()
print ("over2")

                                   线程对比进程
#对比进程启动时间

from multiprocessing import Process
 
def task():
      print ("threading running")
if __name __ =='__main__':
       t1 = process(target = task)
       t1.start()

print ("over")

from multiprocessing import Process
from threading import Tread

import time

def task():
    # print ("子进程任务“)
      pass

#100个进程时间统计

#if __name__ =='___main__':
       start = time.time()
       ps = []
        for i in range(100):
              p = Process(target = task)
              p . start()
              ps.append (p)
       for p in ps:
              p.join()
       print (time.time()-start)


#100个线程

start = time.time()

ts = []
for i in range(100):
      t = Thread(target = task)
      t.start()
      ts.append(t)
for t in ts:
      t .join()
print(time.time()-start)

 

#线程间资源共享

from threading import Thread

x = 100

def task():
      print ("run")
      global x
     x = 0


t= Thread(target = task)
t.start()
t.join()

print (x)
print ("over")

 

守护线程

守护线程
守护线程会在所有非守护线程结束后结束
当所有非线程结束后 守护线程也跟着结束了

#进程 守护进程会在被守护进程死亡跟着死亡
同一个进程 可以有多个守护进程


form threading import Thread
import time

def task():
       print("sub thread run...")
       time.sleep(3)
       print ("sub thread over....")

t = Thread (target = task)
t.setDaemon(True)
t.start()

t = Thread(target = task)
t.setDaemon(True)
t.start()
print ("over")


from threading import Thread
import time

def task():
       print ("子线程运行。。”)
       time.sleep(1)
       print ("子线程结束“)
t = Thread(target = task)
t.setDaemon (True)
t.start()
#time.sleep(0.1)
print ("over")

线程中常用属性
from threading import Thread,current_thread,enumerate,active_count
import os
def task():
      print("running")
      print (active_count())
t1 = Thread (target = task)
t1.start()

#获取所有线程对象列表
print(enumerate)
#获取当前线程对象
print(current_thread())
#获取当前正在运行的线程个数
print(active_count())


线程互斥互锁
       什么时候用锁 当多个进程或多个线程需要同时修改同一份数据时,可能会造成数据的错乱,所以必须得加锁


import time
from threading import Thread,Lock

lock = Lock()

def task():
      lock.acquire()
      global a  #在局部修改全局变量时 需要使用global
      temp = a-1
      time.sleep(0.01)
      a = temp
      lock.release()

ts = []
for i in range(100):
     t =Thread (target = task)
     t.start()
     ts.append(t)

for t in ts:
      t.join()


型号量
     其实也是一种锁 ,特点是可以设置一个数据可以被几个线程(进程)共享
与普通锁的区别
     普通锁一旦加锁 则意味着这个数据在同一时间只能被一个线程使用
     信号量 可以让这个数据在同一时间只能被多个线程使用

使用场景,可以限制一个数据被同时访问的次数,保证程序正常运行

from threading import Semaphre,Thread,current_thread
import time,random
sem = Semaphore(3)

def task ():
      sem.acquire()
      print ("%s run...." %current_thread())
      time.sleep(3)
      sem.release()

for i in range(10):
     t = Thread(target = task)
     t.start()


守护进程的使用

生产者与消费者模型

吃热狗 与 做热狗

import time,random
from multiprocessing import Process,JoinableQueue
def eat_hotdog(name,q):
       while True:
       res = q.get()
       print("%s 吃了%s" %(name,res))
       time.sleep(random.randint(1,2))
       q.task_done() #记录已经被处理的数据的数量

def make_hotdog(name,q):
       for i in range (1,6):
             time.sleep(random.randint(1,2))
             print("%生产了第%s个热狗”%(name,i)
             res = "%s 的%s个热狗” %(name ,i)
             q.put(res)

if __name__ == '__main__':
     q = JoinableQueue()
       #生产者1
      c1 = Process(target = make_hotdog,args =("万达热狗店“,q)
      c1.start()

       #生产者2       c2= Process(target = make_hotdog,args =("宝山热狗店“,q)
       c2.start()
 
       # 消费者
        p2 = process(target = eat_hotdog,args = ("李亚光”,q)
        p2.start()
  
        #首先保证生产者全部生产完成
        c1.join()
        c2.join()

        #保证队列中的数据全部被处理了        q.join() #明确生产方已经不会再生产数据了