多线程

一.什么是线程?

线程就是程序的执行线路

相当于一条流水线,其包含了程序的具体执行步骤

操作系统比喻为一个工厂,进程就是车间,线程就是流水线

 

线程和进程的关系?

进程中包含了运行该程序的所有资源

进程是一个资源单位,线程cpu的最小执行单位

每个进程一旦被创建,就默认开启了一条线程,称之为主线程

一个进程可以包含多个线程

进程包含线程而线程依赖于进程

 

为什么使用线程?

为了提高程序效率

不用进程是因为进程对操作系统的资源消耗非常高

 

线程是如何提高效率?

多线程可以使cpu在一个进程内进行切换,从而提高cpu占用率

多线程提高工作效率原理?

默认情况下每个进程都有且只有一个主线进程,执行代码时如果遇到IO操作系统就会切换到其他应用程序,这就降低了当前应用程序的效率.

如果含有多线程,cpu切换是在不同线程之间进行切换,加入只有两个线程,每个线程被切换到的几率为二分之一,如果一个的应用程序开启了子线,总共就有了三条线程,那么该应用程序被切到的几率就变成了三分之二!

 

什么时候开启多线程?

当程序中遇到IO的时候

 

如何使用?

两种开启线程的方式

①实例化Thread类

from threading import Thread
def task():
    print('你好!')
t = Thread(target=task)
t.start()
print('over')

②继承Thread类覆盖run方法

from threading import Thread
class Mythread(Thread):
    def run(self):
        print('你好!')
t = Mythread()
t.start()
print('over')

 

进程和线程的区别?

①进程对操作系统的资源消耗非常高,而线程非常低(比进程低10-100倍)

#100个进程时间统计
from multiprocessing import Process
import time
def task():
  pass
if __name__ == '__main__':
  start_time = 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_time)
结果:6.828858137130737

#100个线程时间统计
from threading import Thread
import time
def task():
  pass
start_time = 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_time)
结果:0.01562190055847168

 ②在同一个进程多个线程之间资源是共享的

from threading import Thread
a = 0
def task():
    print('run....')
    global a
    a = 100
t = Thread(target=task)
t.start()
t.join()
print(a)
print('over')
结果:
run....
100
over

二.守护线程

守护线程会在所有非守护线程结束后结束

同一个进程可以有多个守护线程

from threading import Thread
import time
def task():
    print('子线程开始!')
    time.sleep(1)
    print('子线程结束!')
t = Thread(target=task)
#t.daemon = True
t.setDaemon(True)
t.start()
print('over')
#结果:
子线程开始!
over

三.线程中常用的属性

from threading import Thread
import os
def task():
    print('running')
    print(os.getpid())
t1 = Thread(target=task)
t1.start()
t2 = Thread(target=task)
t2.start()
结果:
running
1056
running
1056
在不同线程中获取到的进程ID是相同的
from threading import Thread
def task():
    print('running')
t1 = Thread(target=task)
t1.start()
print(t1.is_alive())
print(t1.isAlive())
结果:True True 这两个是一样的
from threading import Thread,current_thread,enumerate,active_count
def task():
    print('running')
    print(current_thread()) #获取当前线程对象
    print(active_count()) #当前正在运行的线程数量 结果:2
t1 = Thread(target=task)
t1.start()
print(t1.getName()) #获取该线程的名字
print(enumerate()) #获取所有线程对象
print(active_count()) #当前正在运行的线程数量 结果:1

四.线程互斥锁

什么时候用锁?

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

from threading import Thread,Lock
import time
lock = Lock()
a = 100
def task():
    lock.acquire()
    global a
    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()
print(a)

五.信号量

信号量:其实也是一把锁,特点是可以设置一个数据可以被几个线程(进程)共享

与普通锁的区别:

普通锁一旦加锁,意味着数据在同一时间只能被一个线程使用

信号量:可以让这个数据再同一时间被多个线程使用

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

from threading import Thread,Semaphore,current_thread
import time
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()

 

进程中 队列守护进程的应用 生产者消费者模型 :思聪吃热狗

from multiprocessing import Process,JoinableQueue
import time,random
def make_hotdog(name,q):
    for i in range(1,6):
        time.sleep(random.randint(1,2))
        print('%s烹饪出来了第%s个热狗'%(name,i))
        res = '%s的第%s个热狗'%(name,i)
        q.put(res)
def eat_hotdog(name,q):
    while True:
        res = q.get()
        print('%s吃了%s'%(name,res))
        time.sleep(random.randint(1,2))
        q.task_done() #记录已经被处理的数据的数量
if __name__ == '__main__':
    q = JoinableQueue()
    #生产者1
    m1 = Process(target=make_hotdog,args=('万达热狗店',q))
    m1.start()
    #生产者2
    m2 = Process(target=make_hotdog,args=('京东热狗店',q))
    m2.start()
    #消费者
    e = Process(target=eat_hotdog,args=('思聪',q))
    e.daemon = True  #设置消费者为守护进程
    e.start()
    #保证生产者全部生产完成
    m1.join()
    m2.join()

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

  

posted @ 2019-01-02 18:30  Zhuang_Z  阅读(107)  评论(0编辑  收藏  举报