博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第三十章 网路编程------线程
阅读量:4611 次
发布时间:2019-06-09

本文共 3974 字,大约阅读时间需要 13 分钟。

1.什么是线程

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

线程和进程的关系 :

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

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

  线程才是真正的执行单位

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

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

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

为什么需要线程:

  目的:提高效率

  就像以一个车间,如果产量跟不上,就再创建一条流水线

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

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

如何使用:

使用方法与进程一样

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

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")

# 使用方法和多进程一模一样 开启线程的代码可以放在任何位置 开启进程必须放在判断下面

线程的特点:

  创建开销小

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

  多个线程之间,是平等的没有父子关系   所有线程的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()

 

 

 

转载于:https://www.cnblogs.com/sry622/p/10974544.html

你可能感兴趣的文章
Word截图PNG,并压缩图片大小
查看>>
Python项目对接CAS方案
查看>>
mysql产生随机数
查看>>
编程风格
查看>>
熟悉常用的Linux命令
查看>>
易之 - 我是个大师(2014年3月6日)
查看>>
Delphi中窗体的事件
查看>>
file_get_contents()获取https出现这个错误Unable to find the wrapper “https” – did
查看>>
Error:Syntax error: redirection unexpected
查看>>
linux vi编辑器
查看>>
js树形结构-----(BST)二叉树增删查
查看>>
contract
查看>>
FJUT ACM 1899 Largest Rectangle in a Histogram
查看>>
如何删除xcode项目中不再使用的图片资源
查看>>
编写用例文档
查看>>
解决WPF两个图片控件显示相同图片因线程占用,其中一个显示不全的问题
查看>>
寻觅Azure上的Athena和BigQuery (二):神奇的PolyBase
查看>>
编程题练习
查看>>
mac os安装vim74
查看>>
Linux内存管理原理
查看>>