线程理论及其运用

Posted wxl1025

tags:

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

1.线程理论

开启进程:内存中开空间,加载资源与数据,启动一个线程执行代码
线程:依赖于进程,一个进程可以包含多个线程,但是一定有一个主线程,线程才是cpu执行的最小单元
进程:划分空间,加载资源  静态的
线程:执行代码   动态的
进程、线程比较:
1.开启多进程开销非常大,线程开销非常小,与其相差10-100倍
2.开启多进程的速度慢,开启多线程速度快
3.进程之间数据不能直接共享(通过队列可以),同一个进程下的线程之间数据可以共享
多进程并发:开启多个进程,每个进程里面的主线程执行任务
多线程并发:开启一个进程,此进程里面多个线程执行任务

2.开启线程的两种方式

第一种方式
from threading import Thread

def task(name):
    print(f'name is playing basketball')

if __name__ == '__main__':
    t = Thread(target=task,args=('kunkun',))
    t.start()

    print('主线程')
第二种方式
from threading import Thread
class MyThread(Thread):

    def run(self):   # 必须是run,类的约束
        print(f'self.name is running')

if __name__ == '__main__':
    t = MyThread()
    t.start()

    print('主线程')

3.线程与进程对比

1.速度
from threading import Thread

def task(name):
    print(f'name is running')

if __name__ == '__main__':
    t = Thread(target=task,args=('mcsaoQ',))
    t.start()   # 先运行子线程,再运行主线程  =>  线程运行速度比进程快

    print('主线程')
2.pid
from threading import Thread
import os

def task():
    print(f'子线程: os.getpid()')

if __name__ == '__main__':
    t = Thread(target=task,)
    t.start()

    print(f'主线程: os.getpid()')  # 线程的pid一致
3.线程之间共享数据
from threading import Thread

x = 1000

def task():
    global x
    x = 0

if __name__ == '__main__':
    t = Thread(target=task)
    t.start()

    print(x)  # x = 0

4.线程方法

from threading import Thread
import threading

def task(name):
    print(f'name is playing basketball')

if __name__ == '__main__':

    t = Thread(target=task,args=('kunkun',),name='线程1')  # 给该对象添加name属性
    t.start()
    # 线程对象方法:
    print(t.is_alive())  # 判断该对象是否活跃
    t.setName('线程2')  # 给该对象添加name属性
    print(t.getName())  # 查看该对象name属性
    print('主线程')
    # threading模块的方法:
    print(threading.current_thread().name)   # 查看当前线程name属性,主进程为MainThread,子进程为该进程name属性
    print(threading.enumerate())  # 返回一个列表,放置的是所有活跃的线程对象
    print(threading.active_count())  #获取活跃的线程数量

5.守护线程

from threading import Thread
import time

def task(name):
    print(f'name is playing basketball')

if __name__ == '__main__':
    t = Thread(target=task,args=('kunkun',))
    t.daemon = True
    t.start()

    print('主线程')  #守护线程随主线程结束而结束
与进程的不同之处:
from threading import Thread
import time

def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(2)
    print("end456")

if __name__ == '__main__':

    t1=Thread(target=foo)
    t2=Thread(target=bar)

    t1.daemon = True
    t1.start()
    t2.start()
    print("main")
多线程存在于同一个空间、同一个进程中,主线程是进程空间存活在内存中的必要条件
=>  主线程必须要等待所有的子线程全部结束之后,才执行完毕,进程再消失
=> 主线程必须等待所有的非守护线程结束才结束,守护线程必须等待主线程结束才结束
=> 守护线程必须等待所有的非守护线程以及主线程结束才结束

6.互斥锁

from threading import Thread
import time
x = 10

def task():
    global x
    temp = x
    time.sleep(1)  # 并发,每个线程获取的x都是10,最终x = 9
    temp -= 1
    x = temp

if __name__ == '__main__':
    t_l = []
    for i in range(10):
        t = Thread(target=task)
        t_l.append(t)
        t.start()

    for i in t_l:
        i.join()

    print(f'主线程x')
解决方式:加锁
from threading import Thread
from threading import Lock
import time
x = 10

def task(lock):
    lock.acquire()  # 串行
    global x
    temp = x
    time.sleep(1)
    temp -= 1
    x = temp
    lock.release()

if __name__ == '__main__':
    lock = Lock()
    t_l = []
    for i in range(10):
        t = Thread(target=task,args=(lock,))
        t_l.append(t)
        t.start()

    for i in t_l:
        i.join()

    print(f'主线程x')

7.死锁现象与递归锁

from threading import Thread
from threading import Lock
import time
lock_A = Lock()
lock_B = Lock()

class MyThread(Thread):


    def run(self):
        self.f1()
        self.f2()

    def f1(self):

        lock_A.acquire()  # 第一个线程睡1秒,使得第二个线程抢到A锁
        print(f'self.name拿到 A锁')

        lock_B.acquire()  # 第二个线程抢B锁,此时B锁以及被第一个线程抢到
        print(f'self.name拿到 B锁')
        lock_B.release()

        lock_A.release()

    def f2(self):

        lock_B.acquire()
        print(f'self.name拿到 B锁')

        time.sleep(1)
        lock_A.acquire()  # 第一个线程抢A锁,此时A锁已经被第二个线程抢到
        print(f'self.name拿到 A锁')
        lock_A.release()

        lock_B.release()


if __name__ == '__main__':
    for i in range(3):
        t = MyThread()
        t.start()

    print('主线程')
程序停住,形成死锁现象
解决方法:递归锁
递归锁是一把锁,锁上有记录,只要acquire一次,就计数1次;release一次,就减1  =>  只要递归锁计数不为0,其他线程不能抢
from threading import Thread
from threading import RLock
import time
# lock_A = RLock()
# lock_B = RLock()
lock_A = lock_B = RLock()

class MyThread(Thread):

    def run(self):
        self.f1()
        self.f2()

    def f1(self):

        lock_A.acquire()
        print(f'self.name拿到 A锁')

        lock_B.acquire()
        print(f'self.name拿到 B锁')
        lock_B.release()

        lock_A.release()

    def f2(self):

        lock_B.acquire()
        print(f'self.name拿到 B锁')

        time.sleep(1)
        lock_A.acquire()
        print(f'self.name拿到 A锁')
        lock_A.release()

        lock_B.release()


if __name__ == '__main__':
    for i in range(3):
        t = MyThread()
        t.start()

    print('主线程')

8.信号量

之前讲的锁都是只允许一个线程或者进程进入,信号量允许多个线程或者进程同时进入
from threading import Thread
from threading import current_thread
from threading import Semaphore
import time
import random
sm = Semaphore(4)

def go_public_wc():
    sm.acquire()
    print(f'current_thread().name正在厕所')
    time.sleep(random.randint(1, 3))
    sm.release()


if __name__ == '__main__':

    for i in range(20):
        t = Thread(target=go_public_wc)
        t.start()

    print('主线程')

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

实体实体集及其运用

Dijkstra算法C#实现及其布线运用

高阶函数及其运用

机器学习 实验一 感知器及其运用

Struts2中的ModelDriven机制及其运用

Struts2中的ModelDriven机制及其运用[转]