多线程

Posted dugd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程相关的知识,希望对你有一定的参考价值。

线程的特点

线程是程序运行中的最基本单元,在一个进程内有且至少有一个进程。

 进程:内存独立,CPU独立,速率低共享数据难,安全性高

 线程:内存共享,CPU使用独立,是cpu最小的执行单位

线程的创建方法

1.直接实例化Thread类

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

    task()
    #执行顺序不固定 如果开启线程速度足够快  可能子线程先执行
    print("主线程over")
    print("1",current_thread())

2.创建类覆盖Thread中的run方法

class MyThread(Thread):
    def run(self):
        print("子线程run!")
m = MyThread()
m.start()
print("主线over")

使用方法和进程一样,但是开启线程的代码可以放在任何位置,开启进程的方法只能放在__name__==__main__中

在同一进程中线程间数据共享

from threading import Thread

a = 10
def task():
    global a
    print("子 running...")
    a = 20

t1 = Thread(target=task)
t1.start()

t1.join() # 主线程等待子线执行完毕
print(a)

==》
子 running...
20

进程与线程效率

开启一百个进程

def task():
    pass

if __name__ == __main__:
    st_time=time.time()
    for a in range(100):
        
        t=Process(target=task)
        t.start()

    print(time.time()-st_time)

==3.447035074234009  开启一百个进程花费的时间

开启一百个线程

def task():
    pass

if __name__ == __main__:
    st_time = time.time()
    for a in range(100):

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

    print(time.time()-st_time)
    print(over)
==0.014977693557739258

由此可见线程的开销远远小于进程的开销

守护线程

def task():
print(‘1run‘)
time.sleep(3)
print(‘1over‘)

def task1():
print(‘2run‘)
time.sleep(6)
print(‘2over‘)

t=Thread(target=task)
t1=Thread(target=task1)
t.start()
t1.daemon=True
t1.start()
print(‘over‘)
==>
1run
2run
over
1over

主线程代码执行完后不会立即结束,会等待其他非守护进程

死锁

当程序出现了不止一把锁,分别被不同的线程持有, 有一个资源要想使用必须同时具备两把锁这时候程序就会进程无限卡死状态 ,这就称之为死锁

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() ==》 Thread-1抢到了盘子 Thread-2抢到了筷子

如上所示,两个锁可以看作两个许可,线程需要同时拿到两把锁才可以正常运行,当两个线程各拿到一把锁的时候双方都无法正常进行下去,这就出现了死锁

如何避免死锁问题  
        锁不要有多个,一个足够
        如果真的发生了死锁问题,必须迫使一方先交出锁

Rlock

称之为递归锁或者可重入锁,Rlock不使用用来解决死锁问题的

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

信号量

可以现在被锁定的代码 同时可以被多少线程并发访问

用途: 仅用于控制并发访问   并不能防止并发修改造成的问题

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

 

以上是关于多线程的主要内容,如果未能解决你的问题,请参考以下文章

线程学习知识点总结

多个请求是多线程吗

python小白学习记录 多线程爬取ts片段

多线程编程

多线程编程

python多线程