python-多任务编程01-线程(threading)

并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)

并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的

线程

python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用

基本线程调用实例:

import time
import threading


def dancing():
    for i in range(1, 4):
        print('跳舞中%d' % i)
        time.sleep(0.5)
    print('dancing 线程结束')


def singing():
    for i in range(1, 5):
        print('唱歌中%d' % i)
        time.sleep(0.5)
    print('singing 线程结束')


def main():
    # 创建子线程对象
    t1 = threading.Thread(target=dancing)
    t2 = threading.Thread(target=singing)
    # 子线程开始执行
    t1.start()
    t2.start()
    # 查看正在运行的子线程数量
    while True:
        length = len(threading.enumerate())
        print('当前运行的线程数为:%d' % length)
        if length <= 1:
            break
        time.sleep(0.2)


if __name__ == '__main__':
    main()

继承Thread类自定义类调用实例:

import threading
import time


class DancingThread(threading.Thread):
    def run(self):
        for i in range(1, 3):
            print('线程名:%s,正在跳舞:。。。%d' % (self.name, i))
            time.sleep(0.5)
        print('
跳舞线程结束')


class SingingThread(threading.Thread):
    def run(self):
        for i in range(1, 5):
            print('线程名:%s,正在唱歌:。。。%d' % (self.name, i))
            time.sleep(0.5)
        print('唱歌线程结束')


def main():
    # 创建Thread对象
    dancing = DancingThread()
    sing = SingingThread()
    # 调用run方法,开启线程
    dancing.start()
    sing.start()


if __name__ == '__main__':
    main()

线程共享全局变量

  • 在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
  • 缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)
  • 假设两个线程t1和t2都要对全局变量g_num(默认是0)进行加1运算,t1和t2都各对g_num加10次,g_num的最终的结果应该为20。
  • 但是由于是多线程同时操作,有可能出现下面情况:
    1. 在g_num=0时,t1取得g_num=0。此时系统把t1调度为”sleeping”状态,把t2转换为”running”状态,t2也获得g_num=0
    2. 然后t2对得到的值进行加1并赋给g_num,使得g_num=1
    3. 然后系统又把t2调度为”sleeping”,把t1转为”running”。线程t1又把它之前得到的0加1后赋值给g_num。
    4. 这样导致虽然t1和t2都对g_num加1,但结果仍然是g_num=1
import threading
import time

g_num = 0


class DancingThread(threading.Thread):
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):
        global g_num
        for i in range(self.num):
            g_num += 1
        print('跳舞线程结束,g_num:%d' % g_num)


class SingingThread(threading.Thread):
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):
        global g_num
        for i in range(self.num):
            g_num += 1
        print('唱歌线程结束,g_num:%d' % g_num)


def main():
    # 创建Thread对象
    dancing = DancingThread(1000000)
    sing = SingingThread(1000000)
    # 调用run方法,开启线程
    print('初始g_num: %d' % g_num)
    dancing.start()
    sing.start()
    # 等待子线程运行完
    while len(threading.enumerate()) > 1:
        time.sleep(1)
    print('线程结束后g_num: %d' % g_num)


if __name__ == '__main__':
    main()

运行结果为:

初始g_num: 0
跳舞线程结束,g_num:1292807
唱歌线程结束,g_num:1712212
线程结束后g_num: 1712212

使用互斥锁解决线程冲突

# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()
import time
import threading
g_num = 0


def dancing(num, mutex):
    global g_num
    for i in range(num):
        # 上锁
        mutex.acquire()
        # 计算
        g_num += num
        # 解锁
        mutex.release()

    print('dancing 线程结束,num值: %d' % g_num)


def singing(num, mutex):
    global g_num
    for i in range(num):
        # 上锁
        mutex.acquire()
        # 计算
        g_num += num
        # 解锁
        mutex.release()

    print('dancing 线程结束,num值: %d' % g_num)


def main():
    print('初始值:%d' % g_num)
    # 创建锁对象
    mutex = threading.Lock()
    # 创建子线程对象
    t1 = threading.Thread(target=dancing, args=(1000000, mutex, ))
    t2 = threading.Thread(target=singing, args=(1000000, mutex, ))
    # 子线程开始执行
    t1.start()
    t2.start()


if __name__ == '__main__':
    main()

运行结果:

初始值:0
dancing 线程结束,num值: 1876392000000
dancing 线程结束,num值: 2000000000000
原文地址:https://www.cnblogs.com/gcxblogs/p/12930887.html