线程,进程,协程(一)线程

注:本文的编程语言使用的是Python。

多任务的概念

  多任务处理是指用户可以在同一时间内运行多个应用程序,

每个应用程序被称作一个任务.Linux、windows就是支持多任务的操作系统。

真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,

操作系统也会自动把很多任务轮流调度到每个核心上执行。

并发:指的是任务数多雨cpu核数,通过操作系统的各种任务调度算法,实现用多个任务

“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)

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

线程

  线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。

一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,

是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,

但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

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

多线程

#coding=utf-8
import threading
import time
def test():
    print("你好,")
    time.sleep(1)
if __name__ == "__main__":
    for i in range(5):
        t = threading.Thread(target=test)
        t.start() #启动线程,即让线程开始执行

说明

使用了多线程并发的操作,花费时间要短很多

当调用start()时,才会真正的创建线程,并且开始执行

每个线程都有一个唯一标示符,来区分线程中的主次关系

主线程:mainThread,Main函数或者程序主入口,都可以称为主线程

子线程:Thread-x 使用 threading.Thread() 创建出来的都是子线程

线程数量:主线程数 + 子线程数

主线程会等待所有的子线程结束后才结束

#导入sleep模块,ctime模块,线程threading模块
from time import sleep,ctime
import  threading

#设置多线程的运行程序函数
def say():
    for i in range(3):
        print("你好啊,我的名字是")
        sleep(1)
def say2():
    for i in range(3):
        print("年华终归属时光")
        sleep(1)
#多线程的带参数传递
def sing(a,b,c):
    print("----sing----a = %d, b = %d,c = %d" % (a, b, c))
    for i in range(3):
        print("一杯酒两角眼...")
        sleep(1)
if __name__ == '__main__':
    #将say,say2封装为线程并让其启动
    print("---开始计时----%s"%ctime())
    a1 = threading.Thread(target=say)
    a2 = threading.Thread(target=say2)
    #使用args传递参数
    a3 = threading.Thread(target=sing,args=(10,100,100))
    #使用kwargs传递参数
    a4 = threading.Thread(target=sing, kwargs={"a": 10, "b": 100, "c": 100} )
    # 设置为守护线程(如果主线程结束了,也随之结束)
    a1.setDaemon(True)
    a1.start()
    a2.start()
    a3.start()
    a4.start()
    print('---计时结束---%s'%ctime())
    #统计当前正在运行的线程数量
    while True:
        length=len(threading.enumerate())
        print("当前运行的线程数为%d"%length)
        if length <=1:
            break
        sleep(1)

多线程程序的执行顺序是不确定的。当执行到sleep语句时,线程将被阻塞(Blocked),

到sleep结束后,线程进入就绪(Runnable)状态,等待调度。而线程调度将自行选择一个线程执行。

上面的代码中只能保证每个线程都运行完整个run函数,但是线程的启动顺序、run函数中每次循环的执行顺序都不能确定。

 总结

每个线程默认有一个名字,尽管上面的例子中没有指定线程对象的name,但是python会自动为线程指定一个名字。

当线程的run()方法结束时该线程完成。

无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。

守护线程

  守护线程:如果在程序中将子线程设置为守护线程,则该子线程会在主线程结束时自动退出,

设置方式为thread.setDaemon(True),要在thread.start()之前设置,默认是false的,也就是主线程结束时,子线程依然在执行。

设置守护线程:

# 设置为守护线程(如果主线程结束了,也随之结束)

线程.setDaemon(True)

线程执行代码的封装(自定义线程类)

通过使用threading模块能完成多任务的程序开发,为了让每个线程的封装性更完美,所以使用threading模块时,往往会定义一个新的子类class,只要

继承threading.Thread

重写run方法

python的threading.Thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。

而创建自己的线程实例后,通过Thread类的start方法,可以启动该线程,

交给python虚拟机进行调度,当该线程获得执行的机会时,就会调用run方法执行线程。

super(MyThread, self).__init__() 调用父类的构造方法

**** super用法 ****

super(type【类】,object-or-type 【类,一般是 self】)

'''python的threading.Thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。
而创建自己的线程实例后,通过Thread类的start方法,可以启动该线程,交给python虚拟机进行调度,
当该线程获得执行的机会时,就会调用run方法执行线程。'''
#conding=utf-8
import time
import  threading

class MyThread(threading.Thread):

    def __init__(self,name,city):
        super(MyThread,self).__init__()
        self.name = name
        self.city = city
    def run(self):
        for i in range(3):
            time.sleep(1)
            msg = "i'm "+self.name+"来自"+self.city+str(i)
            print(msg)
t = MyThread("年华终归属时光","北京")
t.start()

多线程共享全局变量

from threading import Thread
import time

g_num = 100

def work1():
    global g_num
    for i in range(3):
        g_num += 1

    print("----in work1, g_num is %d---"%g_num)


def work2():
    global g_num
    print("----in work2, g_num is %d---"%g_num)


print("---线程创建之前g_num is %d---"%g_num)

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

#延时一会,保证t1线程中的事情做完
time.sleep(1)

t2 = Thread(target=work2)
t2.start()

列表当做实参传入线程中

from threading import Thread
import time

def work1(nums):
    nums.append(44)
    print("----in work1---",nums)


def work2(nums):
    #延时一会,保证t1线程中的事情做完
    time.sleep(1)
    print("----in work2---",nums)

g_nums = [11,22,33]

t1 = Thread(target=work1, args=(g_nums,))
t1.start()

t2 = Thread(target=work2, args=(g_nums,))
t2.start()

多线程共享变量遇到的问题:
  假设两个线程t1和t2都要对全局变量g_num(默认是0)进行加1运算,t1和t2都各对g_num加10次,g_num的最终的结果应该为20。
但是由于是多线程同时操作,有可能出现下面情况:
在g_num=0时,t1取得g_num=0。此时系统把t1调度为”sleeping”状态,把t2转换为”running”状态,t2也获得g_num=0
然后t2对得到的值进行加1并赋给g_num,使得g_num=1
然后系统又把t2调度为”sleeping”,把t1转为”running”。线程t1又把它之前得到的0加1后赋值给g_num。
这样导致虽然t1和t2都对g_num加1,但结果仍然是g_num=1
如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确
线程的join()方法的使用
假如有A、B两个线程同时执行,如果想要让A线程执行完成后,再执行线程B,那么A线程可以调用join()方法来完成,
Join方法:如果一个线程在执行过程中要调用另外一个线程,并且等到其完成以后才能接着执行,
线程名.join()

猜你喜欢

转载自blog.csdn.net/qq_36828513/article/details/81118044