多任务编程(一)

多任务编程(一)

一、threading模块

1、如何使用threading模块创建子线程

(1)创建子线程之1:

import threading
import time

def hello():
    print("hello world!")
    time.sleep(5)

# 主线程
def main():
    for i in range(0, 1):
        t1 = threading.Thread(target=hello)  # 定义一个子线程,这里的target用于传入函数名称
        t1.start()   # 创建并启动一个子线程,让线程开始执行


if __name__ == "__main__":
    main()

当调用thread的时候并不会创建子线程,当调用thread创建的对象的start方法时,创建并执行线程

(2)创建子线程之2:

import threading
import time


# 通过定义一个类,该类必须继承Thread类,来实现子线程的创建
class Mythread(threading.Thread):
    # Thread的方法start会自动调用run方法,因此必须定义run方法
    def run(self):
        for i in range(5):
            time.sleep(5)
            msg = self.name + "@" + str(i)
            print(msg)
            print(threading.enumerate())


if __name__ == "__main__":
    t = Mythread()
    print(threading.enumerate())
    t.start()
    print(threading.enumerate())

2、查看线程数量

使用threading.enumerate()方法查看当前程序中的所有线程

import threading
import time


def test1():
    for i in range(10):
        print("test1-----")
        time.sleep(2)

# 创建子线程的函数运行结束,则子线程也就结束
def test2():
    for i in range(10):
        print("test2---------")
        time.sleep(2)


def main():
    print("----开始时间-----:%s" % time.ctime())

    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)

    t1.start()
    t2.start()
    time.sleep(2)

    while True:
        length = len(threading.enumerate())     # 获取当前程序里的所有线程,返回一个列表
        print("当前运行的线程个数:%s" % length)
        print("线程名称:")

        for temp in threading.enumerate():
            print(temp)
        time.sleep(10)

        if length <= 1:
            break


if __name__ == "__main__":
    main()

3、多线程共享全局变量

在一个函数中,对全局变量进行修改时,是否需要使用global进行说明?
主要在于:这个操作有没有对全局变量的执行指向进行修改
(1)如果修改了执行指向,则必须使用global说明
(2)如果没有修改执行指向,仅仅是修改了指向的内容,则不必使用global声明

import threading
import time


def test1(temp):
    temp.append(33)
    print("-----in test1 nums=%s----" % str(temp))


def test2(abc):
    print("-----in test3 nums%s----" % str(abc))



def test3(temp):
    global nums
    nums += temp
    print("-----in test3 nums=%s----" % str(nums))


nums = [22, 55]


if __name__ == "__main__":
    t1 = threading.Thread(target=test1, args=(nums,))
    t2 = threading.Thread(target=test2, args=(nums,))
    t3 = threading.Thread(target=test3, args=(nums,))

    t1.start()
    time.sleep(2)

    t2.start()
    time.sleep(2)

    t3.start()
    time.sleep(2)

    print("-----main ----nums=%s----" % str(nums))

如果对于该不该使用global时机不清的话,建议使用pycharm来写代码,它会主动提示这个问题。

4、线程同步

(1)资源竞争
import threading
import time

num = 0


def test1(temp):
    global num
    for i in range(temp):
        num += 1
    print("-----in test1 num=%s----" % str(num))


def test2(temp):
    global num
    for i in range(temp):
        num += 1
    print("-----in test2 num=%s----" % str(num))


def test3(temp):
    global num
    for i in range(temp):
        num += 1
    print("-----in test2 num=%s----" % str(num))


if __name__ == "__main__":
    nums = 1000000
    t1 = threading.Thread(target=test1, args=(nums,))
    t2 = threading.Thread(target=test2, args=(nums,))
    t3 = threading.Thread(target=test3, args=(nums,))

    t1.start()
    t2.start()
    t3.start()

    print("-----main ----num=%s----" % str(num))

执行结果:

-----main ----num=1074075----
-----in test1 num=1177315----
-----in test2 num=1426154----
-----in test2 num=1602839----

学过操作系统的应该很清楚为什么会这样,这里不再赘述

(2)互斥锁
  • 一种加锁方式,把锁加在循环外面:
import threading
import time

num = 0


def test1(temp):
    global num
    # 上锁,如果没有上锁则直接上锁
    # 如果已经有线程先一步上锁了,则堵塞,直到解锁为止
    mutex.acquire()
    for i in range(temp):
        num += 1
    # 解锁
    mutex.release()
    print("-----in test1 num=%s----" % str(num))


def test2(temp):
    global num
    # 上锁,如果没有上锁则直接上锁
    # 如果已经有线程先一步上锁了,则堵塞,直到解锁为止
    mutex.acquire()
    for i in range(temp):
        num += 1
    # 解锁
    mutex.release()
    print("-----in test2 num=%s----" % str(num))


def test3(temp):
    global num
    # 上锁,如果没有上锁则直接上锁
    # 如果已经有线程先一步上锁了,则堵塞,直到解锁为止
    mutex.acquire()
    for i in range(temp):
        num += 1
    # 解锁
    mutex.release()
    print("-----in test3 num=%s----" % str(num))


mutex = threading.Lock()

if __name__ == "__main__":
    nums = 1000000
    t1 = threading.Thread(target=test1, args=(nums,))
    t2 = threading.Thread(target=test2, args=(nums,))
    t3 = threading.Thread(target=test3, args=(nums,))

    t1.start()
    t2.start()
    t3.start()

    print("-----main ----num=%s----" % str(num))

执行结果:

-----main ----num=148062----
-----in test1 num=1000000----
-----in test2 num=2000000----
-----in test3 num=3000000----

反复执行该程序,可以看到,虽然main那里的num会发生变化,但是其余的不会(这和操作系统的调度算法有关系,一般来说:test1、test2、test3这三个子线程的优先级是一样,应该是按照创建时间的先后进入队列,所以执行顺序是:test1、test2、test3)这是因为,主线程运行到print时,num还没有加完就直接被读取输出了

  • 另一种加锁方式,把锁加在循环内部:
import threading
import time

num = 0


def test1(temp):
    global num
    for i in range(temp):
        # 上锁,如果没有上锁则直接上锁
        # 如果已经有线程先一步上锁了,则堵塞,直到解锁为止
        mutex.acquire()
        num += 1
        # 解锁
        mutex.release()
    print("-----in test1 num=%s----" % str(num))


def test2(temp):
    global num
    for i in range(temp):
        # 上锁,如果没有上锁则直接上锁
        # 如果已经有线程先一步上锁了,则阻塞,直到解锁为止
        mutex.acquire()
        num += 1
        # 解锁
        mutex.release()

    print("-----in test2 num=%s----" % str(num))


def test3(temp):
    global num
    for i in range(temp):
        # 上锁,如果没有上锁则直接上锁
        # 如果已经有线程先一步上锁了,则阻塞,直到解锁为止
        mutex.acquire()
        num += 1
        # 解锁
        mutex.release()
    print("-----in test3 num=%s----" % str(num))


mutex = threading.Lock()

if __name__ == "__main__":
    nums = 1000000
    t1 = threading.Thread(target=test1, args=(nums,))
    t2 = threading.Thread(target=test2, args=(nums,))
    t3 = threading.Thread(target=test3, args=(nums,))

    t1.start()
    t2.start()
    t3.start()

    print("-----main ----num=%s----" % str(num))

执行结果:

-----main ----num=30463----
-----in test1 num=2934771----
-----in test3 num=2994796----
-----in test2 num=3000000----

可以看到和方法一的不一样,这里稍微解释一下:
假设第一个上锁的时test1线程,它在上锁之后,执行+1操作,此时test2、test3都处在阻塞状态,但是随后test1解锁,于是按照算法,test2或者test3会对其进行上锁,这么一来test1也会处于阻塞状态,最后输出的时候,就不再是1000000了

(3)银行家算法
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值