网络编程---第十一课:线程,共享资源,锁

2021-03-09  本文已影响0人  少年已老4941

参考连接:https://blog.csdn.net/qq_37615098/article/details/83933614

## 线程的概念

**进程的概念:运行着的程序

每个进程里面至少有一个线程

线程是操作系统创建的,用力啊控制代码执行的数据结构

线程就像代码的执行许可证**

**单线程程序。主线程的入口就是代码的开头

主线程顺序往下执行,直到所有的代码都执行完**

**

## 概念对应(银行里面办理业务)

**

***一个服务窗口 = CPU的一个核

客户 = 进程(运行着的程序)

调度员 = 操作系统(OS)

服务号 = 线程

调度员分配服务号给客户 = OS分配线程给进程代码

服务窗口给客户办理业务 = CPU核心执行线程代码***

## 调度的概念

        调度员分配窗口给客户

        一个客户不一定占用一个窗口直到它结束

        比如需要很长时间填写表格

        这是可以让下一个客户办理

        先前的客户填好了表格,在继续

    操作系统不会让一个线程一直占用CPU的

## 进程里的多线程

**线程库**

***代码通过系统调用,请求os分配一个新的线程

python里面使用封装好的库,python3只有threading,是标准库里面的

    thread

    threading

    都可以用来创建和管理线程

    thread比较底层

    threading是thread模块的扩展,提供了很多线程同步功能,使用起来更加方便强大***

例子:

    print("main thread start.")

    import threading

    from time import sleep

    def thread1_entry():

        print("child thread 1,start")

        sleep(15)

        print("child thread 1,end")

    t1 = threading.Thread(target=thread1_entry)    #Thread是一个类Thread()是实例化一个类,传入初始化方法的参数,target传的是这个函数的名字,不是调用。不加括号是函数的对象,target指定了线程对象的入口函数。函数的名字,并没有加括号,意味着target传入的值是一个函数对象,如果加(),target就变成了函数调用的返回值。执行起来的时候,入口函数就是thread1_entry,t1只是对应一个thread模块,要想执行要调用thread的start方法。新的线程执行入口函数里面的代码。

    t1.start()    #t1是Thread的实例对象,从这个点开始就启动了一个新的线程

    sleep(10)    #主线程要sleep10秒    主线程先结束

    print("main thread end.")

**#结果**

    main thread start.

    child thread 1,start

    main thread end.

    child thread 1,end

***有些场景是:主线程要等待子线程执行完,比如子线程爬去数据,主线程分析数据、

要等到子线程结束(线程的.join()方法)***

    import threading

    from time import sleep,ctime,time

    def thread1_entry(nsec):

        print("child thread 1,start at:",ctime())

        sleep(nsec)

        print("child thread 1,end at:",ctime())

    def thread2_entry(nsec):

        print("child thread 2,start at:",ctime())

        sleep(nsec)

        print("child thread 2,end at:",ctime())

    print("main thread start.")

    #创建线程对象,指定了新线程的入口函数,args是传入入口函数的参数

    t1 = threading.Thread(target=thread1_entry,args=(1,))    #Thread是一个类Thread()是实例化一个类,传入初始化方法的参数

    t2 = threading.Thread(target=thread2_entry,args=(2,))  #(1,)元组,args=(1,)是入口函数的参数,就是用args传给他,只能传元组,一个元素的时候,一定要加逗号,这里是传入的是时间

    #启动新线程

    t1.start()  #两个线程的实例化。调用start方法

    t2.start()

    start = time()    #验证json等待的时间

    #主线程等待t1线程结束,

    t1.join()

    #主线程等待t2线程结束

    t2.join()

    end = time()        #验证json等待的时间

    print(end-start)        #验证json等待的时间

    print("main thread end.")

#结果:

    # main thread start.

    # child thread 1,start at: Sat Nov 10 18:06:26 2018

    # child thread 2,start at: Sat Nov 10 18:06:26 2018

    # child thread 1,end at: Sat Nov 10 18:06:27 2018

    # child thread 2,end at: Sat Nov 10 18:06:28 2018

    # 2.0

    # main thread end.

多线程使用局部变量不会乱套, 多线程使用全局变量会乱套

## 多线程使用共享数据

## 共享对象的概念

**从例子说起

高铁上的测试

某个时刻只能一个人使用

进入后往往立刻锁门(表示已经被使用)

看到的人,门口排队等待

用完开锁(表示已经使用完了)

排队的人中下一个去使用(重复这个过程)**

**有些资源是某个时刻时刻独占使用的

如果不加锁

    某人使用厕所

    另一个人也进入使用

    发生冲突

锁保证了

    只有一个人去使用

    别人必须等待**

    import threading

    from time import sleep,ctime,time

    #存储支付宝账号余额

    zhifubao = {

        "jcy":100000,

        "liming":5000,

        "wangmin":15000,

        "zhaolei":6500000,

    }

    #线程1:滴滴打车处理,参数是用户账户和扣款金额

    def thread1_didi_pay(account,amount):

        print("* t1:get balance from bank")

        balance = zhifubao[account]    #通过账户把余额取出来,放到一个变量里面

        #下面的sleep(2)表示一些处理过程中需要花上2秒钟

        print("* t1:do something(like discount lookup) for 2 seconds")

        sleep(2)

        print("* t1:deduct")

        zhifubao[account] = balance - amount    #把余额扣掉

    #线程2:余额宝处理,参数是用户账户和当前利息

    def thread2_yuebao_interest(account, amount):

        print("$ t2:get balance from bank")

        balance = zhifubao[account]

        # 下面的sleep(1)表示一些处理过程中需要花上1秒钟

        print("$ t2:do something2...... for 2 seconds")

        sleep(1)

        print("$ t2: add")

        zhifubao[account] = balance + amount    ##余额每天的收益

    t1 = threading.Thread(target=thread1_didi_pay,args=("jcy",10))  #创立两个线程对象

    t2 = threading.Thread(target=thread2_yuebao_interest,args=("jcy",10))

    t1.start()

    t2.start()

    t1.join()

    t2.join()

    print("finally,jcy balance is %s"%zhifubao["jcy"])

#结果

    # * t1:get balance from bank

    # * t1:do something(like discount lookup) for 2 seconds

    # $ t2:get balance from bank

    # $ t2:do something2...... for 2 seconds

    # $ t2: add

    # * t1:deduct

    # finally,jcy balance is 99990

**#应该是10万元**

#多个线程要访问共享数据的时候,特别是要修改数据的时候。我们可以使用**锁对象的机制**。同时只有一个线程处理他的时候,就不会有问题

    import threading

    from time import sleep,ctime,time

    #存储支付宝账号余额

    zhifubao = {

        "jcy":100000,

        "liming":5000,

        "wangmin":15000,

        "zhaolei":6500000,

    }

    #调用Lock函数,返回一个锁对象

    zhifubao_lock = threading.Lock()

    #线程1:滴滴打车处理,参数是用户账户和扣款金额

    def thread1_didi_pay(account,amount):

        #在代码访问共享对象之前,加锁

        #当多个线程同时执行lock.acquire()时,

        #只有一个线程能成功的获取锁,然后继续执行代码

        #其他线程就继续等待,直到获得锁为止

        zhifubao_lock.acquire()

        print("* t1:get balance from bank")

        balance = zhifubao[account]    #通过账户把余额取出来,放到一个变量里面

        #下面的sleep(2)表示一些处理过程中需要花上2秒钟

        print("* t1:do something(like discount lookup) for 2 seconds")

        sleep(2)

        print("* t1:deduct")

        zhifubao[account] = balance - amount    #把余额扣掉

        #访问共享对象释放锁

        #访问结束后,一定要调用Lock对象的release方法,进行解锁操作

        #否则其他等待锁的线程将永远等待下去

        zhifubao_lock.release()

    #线程2:余额宝处理,参数是用户账户和当前利息

    def thread2_yuebao_interest(account, amount):

        zhifubao_lock.acquire()  #代码访问共享对象之前,加锁

        print("$ t2:get balance from bank")

        balance = zhifubao[account]

        # 下面的sleep(1)表示一些处理过程中需要花上1秒钟

        print("$ t2:do something2...... for 2 seconds")

        sleep(1)

        print("$ t2: add")

        zhifubao[account] = balance + amount    ##余额每天的收益

        zhifubao_lock.release()    #访问完共享对象 释放锁

    t1 = threading.Thread(target=thread1_didi_pay,args=("jcy",10))  #创立两个线程对象

    t2 = threading.Thread(target=thread2_yuebao_interest,args=("jcy",10))

    t1.start()

    t2.start()

    t1.join()

    t2.join()

    print("finally,jcy balance is %s"%zhifubao["jcy"])

#结果

    # * t1:get balance from bank

    # * t1:do something(like discount lookup) for 2 seconds

    # * t1:deduct

    # $ t2:get balance from bank

    # $ t2:do something2...... for 2 seconds

    # $ t2: add

    # finally,jcy balance is 100000   

![在这里插入图片描述](https://img-blog.csdnimg.cn/20181110214842734.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3NjE1MDk4,size_16,color_FFFFFF,t_70)

上一篇 下一篇

猜你喜欢

热点阅读