码迷,mamicode.com
首页 > 编程语言 > 详细

第二十九章:初识线程

时间:2019-06-04 19:26:34      阅读:111      评论:0      收藏:0      [点我收藏+]

标签:有一个   oba   位置   自己   不同的   中国   制作   enumerate   enum   

什么是线程

线程是操作系统最小的运算调度单位,被包含在进程中,一个线程就是一个固定的 执行流程 

线程的进程的关系  重点

线程不能单独存在 必须存在于进程中,

进程是一个资源单位,其包含了运行程序所需的所有资源

线程才是真正的执行单位

没有线程,进程中的资源无法被利用起来,所以一个进程至少包含一个线程,称之为主线程

当我们启动一个程序时,操作系统就会自己为这个程序创建一个主线程

线程可以由程序后期开启  ,自己开启线程称之为子线程 

 

为什么需要线程   重点

目的只有一个就是提高效率

就像一个车间 如果产量更不上 就在造一条流水线

当然可以再造一个新车间,那需要把原材料运过去  ,这个过程是非常耗时的 

所以通常情况是创建新的流水线 而不是车间  即 线程

 

如何使用   重点

使用方法和多进程一模一样  

不过开启线程的代码可以放在任何位置  开启进程必须放在判断下面

from threading import Thread,current_thread
import time
?
def task():
   print("2",current_thread())
   print("子线程running")
   time.sleep(10)
   print("子线程over")
?
# 使用方法一 直接实例化Thread类
if __name__ == ‘__main__‘:
   t = Thread(target=task)
   t.start()
   
   # task()
   # 执行顺序不固定 如果开启线程速度足够快 可能子线程先执行
   print("主线程over")
   print("1",current_thread())
?
# 使用方法二 继承Thread 覆盖run方法
class MyThread(Thread):
   def run(self):
       print("子线程run!")
m = MyThread()
print("主线over")
?
# 使用方法和多进程一模一样   开启线程的代码可以放在任何位置 开启进程必须放在判断下面

线程的特点  重点

1.创建开销小

2.同一个进程中的多个线程数据时共享的 

3.多个线程之间,是平等的没有父子关系    所有线程的PID都是相同的 

# 创建线程开销对比
import os
from threading import  Thread
from multiprocessing import Process
?
import time
?
?
def task():
   # print("hello")
   print(os.getpid())
   pass
?
if __name__ == ‘__main__‘:
?
   st_time = time.time()
?
   ts = []
   for i in range(100):
       t = Thread(target=task)
       # t = Process(target=task)
       t.start()
       ts.append(t)
?
   for t in ts:
       t.join()
?
   print(time.time()-st_time)
   print("主over")

 

守护线程  了解

一个线程可以设置为另一个线程的守护线程 

特点:  被守护线程结束后守护线程也随之结束 

# 守护线程会等到所有非守护线程结束后结束  !    前提是除了主线程之外 还有后别的非守护
# 当然如果守护线程已经完成任务 立马就结束了
from threading import Thread
import time
?
def task():
   print("子1running......")
   time.sleep(100)
   print("子1over......")
?
def task2():
   print("子2running......")
   time.sleep(4)
   print("子2over......")
   
t = Thread(target=task)
t.daemon = True
t.start()
?
t2 =Thread(target=task2)
t2.start()
?
print("主over")

线程 互斥锁

共享意味着竞争

线程中也存在安全问题,

多线程可以并发执行,一旦并发了并且访问了同一个资源就会有问题 

解决方案:还是互斥锁 

案例:

from threading import Thread,enumerate,Lock
import time
?
number = 10
?
lock = Lock()
?
def task():
   global number
   lock.acquire()
   a = number
   time.sleep(0.1)
   number = a - 1
   lock.release()
?
for i in range(10):
   t = Thread(target=task)
   t.start()
?
for t in enumerate()[1:]:
   # print(t)
   t.join()
   
print(number)

 

死锁问题

from threading import Lock, current_thread, Thread
?
"""
  死锁问题
  当程序出现了不止一把锁,分别被不同的线程持有, 有一个资源 要想使用必须同时具备两把锁
  这时候程序就会进程无限卡死状态 ,这就称之为死锁
  例如:
      要吃饭 必须具备盘子和筷子   但是一个人拿着盘子 等筷子 另一个人拿着筷子等盘子
   
  如何避免死锁问题  
      锁不要有多个,一个足够
      如果真的发生了死锁问题,必须迫使一方先交出锁
       
"""
import time
# 盘子
lock1 = Lock()
?
# 筷子
lock2 = Lock()
?
def eat1():
   lock1.acquire()
   print("%s抢到了盘子" % current_thread().name)
   time.sleep(0.5)
   lock2.acquire()
   print("%s抢到了筷子" % current_thread().name)
?
   print("%s开吃了!" % current_thread().name)
   lock2.release()
   print("%s放下筷子" % current_thread().name)
?
   lock1.release()
   print("%s放下盘子" % current_thread().name)
?
?
def eat2():
   lock2.acquire()
   print("%s抢到了筷子" % current_thread().name)
?
   lock1.acquire()
   print("%s抢到了盘子" % current_thread().name)
?
?
   print("%s开吃了!" % current_thread().name)
?
?
   lock1.release()
   print("%s放下盘子" % current_thread().name)
   lock2.release()
   print("%s放下筷子" % current_thread().name)
?
?
t1 = Thread(target=eat1)
?
?
t2 = Thread(target=eat2)
?
t1.start()
t2.start()

可重入锁   了解

Rlock  称之为递归锁或者可重入锁

Rlock不是用来解决死锁问题的

与Lock唯一的区别:
Rlock同一线程可以多次执行acquire 但是执行几次acquire就应该对应release几次
   
如果一个线程已经执行过acquire 其他线程将无法执行acquire

 

?
from threading import RLock, Lock, Thread
?
# l = Lock()
#
# l.acquire()
# print("1")
# l.acquire()
# print("2")
?
?
l = RLock()
?
# l.acquire()
# print("1")
# l.acquire()
# print("2")
?
def task():
   l.acquire()
   print("子run......")
   l.release()
?
?
# 主线程锁了一次
l.acquire()
l.acquire()
?
l.release()
l.release()
t1 = Thread(target=task)
t1.start()

信号量  了解

?
"""
信号量 了解
Lock RLock
?
可以现在被锁定的代码 同时可以被多少线程并发访问
Lock 锁住一个马桶 同时只能有一个
Semaphore 锁住一个公共厕所   同时可以来一堆人
?
?
用途: 仅用于控制并发访问   并不能防止并发修改造成的问题
"""
?
from threading import Semaphore, Thread
import time
?
s = Semaphore(5)
def task():
  s.acquire()
  print("子run")
  time.sleep(3)
  print("子over")
  s.release()
?
for i in range(10):
  t = Thread(target=task)
  t.start()

 

 

回顾

多线程 

线程是CPU的最小执行单位, 线程本质是一堆代码构成的执行流程  

线程被包含在进程中,   

进程是一个资源单位,其中存储着该程序运行所需所有资源, 可以比喻为一个车间  

线程就是车间中国一条流水线,上面放的是制作产品的具体方法(就是的代码)

 

一个进程至少有一个线程,操作系统在运行一个程序时 会在进程中自动开启一条线程

一个进程中可以有多个线程

同一个进程中的线程共享进程内的数据  

创建线程速度非常快 开销小

线程之间没有父子关系    都是平等的 

 

 

使用方式和进程一致

学习多线程  多进程 都是为了提高效率 ,通过并发执行多个任务

实现并发的方式,多线程和多进程 

 

 

 

 

 

 

 

 

 

 

 

第二十九章:初识线程

标签:有一个   oba   位置   自己   不同的   中国   制作   enumerate   enum   

原文地址:https://www.cnblogs.com/haojunliancheng/p/10975357.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!