二十九、线程与多线程

一、线程定义及作用

线程:进程线程其实都是虚拟单位,都是用来帮助我们形象的描述某种事物
进程:资源单位(进程开辟一块内存空间,里面可以有多个线程)
线程:执行单位(进程的任务都是线程去执行)
将内存比如成工厂
那么进程就相当于是工厂里面的车间
而你的线程就相当于是车间里面的流水线
ps:每个进程都自带一个线程,线程才是真正的执行单位,进程只是在线程运行过程中
提供代码运行所需要的资源

线程的作用:
开进程:
1.申请内存空间 耗资源
2."拷贝代码" 耗资源

开线程
一个进程内可以起多个线程,并且线程与线程之间数据是共享
ps:开启线程的开销要远远小于开启进程的资源占有
  比如:一个进程在运行过程中遇到阻塞,要么只能等待,
要么就需要多启动一个进程去执行提高运算速度,

这时候 线程 就可以在不多开启进程的情况下,异步去执行其他代码,提高效率
(进程在同一时间只能干一件事,要想同时干几件事就显得无能为力)

  注意:进程是资源分配的最小单位,线程是cpu调度的最小单位
每一个进程中至少有一个线程

二、创建线程的两种方式

from threading import Thread
import time


def task(name):
    print('%s is running' % name)
    time.sleep(3)
    print('%s is over' % name)


# 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内
t = Thread(target=task, args=('egon',))
t.start()  # 告诉操作系统开辟一个线程  线程的开销远远小于进程
# 小的代码执行完 线程就已经开启了
print('')

"""第二种方法:
from threading import Thread
import time


class MyThread(Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print('%s is running' % self.name)
        time.sleep(3)
        print('%s is over' % self.name)


t = MyThread('egon')
t.start()
print('主')
就是继承Thread得来"""

三、线程对象及其他方法

子线程与子线程,主线程都是异步(同时)运行,并且都是同一个进程
from threading import Thread, current_thread, active_count
import time, os


def task(name, i):
    print("%s is runing" % name)
    print("子线程名字:", current_thread().name)  # 子线程名字
    print("子线程进程:", os.getpid())
    time.sleep(1)
    print("%s is over" % name)

# active_count() 当前活跃线程数:
# current_thread().name 线程名字(是主线程或子线程名字)
# os.getpid()查询进程数
t1 = Thread(target=task, args=("engon", 1,)) t2 = Thread(target=task, args=("tank", 2,)) t1.start() t2.start() # t1.join() # t2.join() #等待子线程结束 print("当前正在活跃的线程数:", active_count()) print("主线程名字:", current_thread().name) # print("主线程进程:", os.getpid()) # 只要不是子线程,都是主线程

四、守护线程

主线程的结束也就意味着进程的结束
主线程必须等待其他非守护线程的结束才能结束
(意味子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了)
from threading import Thread, current_thread
import time


def task(i):
    print(current_thread().name)
    time.sleep(i)
    print('GG')


# for i in range(3):
#     t = Thread(target=task,args=(i,))
#     t.daemon = True
#     t.start()
t = Thread(target=task, args=(1,))
t.daemon = True  # 开启子线程守护线程
t.start()
print('')

五、线程之间的通讯

 同一个进程里,所有线程的数据都是共享的,因为都在同一个内存空间(进程开辟的空间)
from threading import Thread


money = 666

def task():
    global money
    money = 777

t = Thread(target=task)
t.start()
t.join()
print(money) #777

六、线程锁(互斥锁)

线程锁:和进程锁使用方法一样,开启多线程中会存在数据不安全(多个线程抢同一个数据)
from threading import Thread, Lock
import time

n = 100

def task(mutex):
    global n
    mutex.acquire()
    tmp = n
    time.sleep(0.1)
    n = tmp - 1
    mutex.release()

t_list = []
mutex = Lock()
for i in range(100):
    t = Thread(target=task, args=(mutex,))
    t.start()
    t_list.append(t)
for t in t_list:
    t.join()
print(n) #0
# 100个线程异步去执行task(),拿到锁以后一个一个运行,保证数据安全
from threading import Thread
import time


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


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


if __name__ == '__main__':
    t1 = Thread(target=foo)
    t2 = Thread(target=bar)
    t1.daemon = True
    t1.start()
    t2.start()
    print("main-------")
小练习
原文地址:https://www.cnblogs.com/wukai66/p/11340709.html