不管进程还是线程,主都会等着子结束而结束这是因为子进程/线程在执行的时候,会暂用一些资源,主就要收回这些资源
线程是系统调度的基本单位,进程是系统资源的基本单位
主线程会等待子线程结束才结束
import threading
import time
def sayHello():
print("------")
time.sleep(1)
for i in range(5):
t = threading.Thread(target=sayHello)
t.start()
print("*******")
Result:
------
------
------
------
------
******* #多个线程执行同一个函数,不会互相影响
#####################使用thread子类完成创建多线程###########
import threading
import time
class myThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
print(self.name+"num"+str(i)) #self.name保存的是当前的线程名字
if __name__ == "__main__":
t = myThread()
t.start() #MyThread没有start方法,为啥可以使用呢,这是threading.Thread中start去调用myThread的run方法
线程的执行顺序:
线程的执行顺序没有固定的,各个线程执行顺序不固定
线程共享全局变量:
线程全局变量是共用的,一个线程的更改其它线程使用也是更改的;而进程是相互独立的,一个进程修改不会对另一个进程产生影响
import time
import threading
g_num = 0
def work1():
global g_num
g_num += 1
print("work1, gum is %d"%g_num)
def work2():
global g_num
print("work2, gum is %d"%g_num)
t1 = threading.Thread(target = work1)
t1.start()
time.sleep(1)
t2 = threading.Thread(target = work2)
t2.start()
result:
work1, gum is 1
work2, gum is 1
列表作为参数传递也可以共享,变量不行需要global
import time
import threading
def work1(g_num):
g_num.append(4)
print("work1, guum is", g_num)
def work2(g_num):
time.sleep(1)
print("work2, guum is", g_num)
g_num = [1,2,3]
t1 = threading.Thread(target = work1, args=(g_num,))
t1.start()
t2 = threading.Thread(target = work2, args=(g_num,))
t2.start()
Result:
work1, guum is [1, 2, 3, 4]
work2, guum is [1, 2, 3, 4]
####互斥锁
当多个线程同时竞争同一个资源的的时候
互斥锁是加的code范围越小越好,加的太多越来越像单任务
比如下面如果在for循环外面加就跟单任务很相似
import threading
g_num = 0
def work1():
global g_num
#这个线程和work2都在抢着对这个锁进行上锁,如果一方的锁上锁成功,那么另一方需要需要一直等待,知道这个锁释放为
for i in range(1000000):
mutex.acquire()
g_num += 1
mutex.release() #解锁
print("work1, guum is %d"%g_num)
def work2():
global g_num
for i in range(1000000):
mutex.acquire()
g_num += 1
mutex.release()
print("work1, guum is %d"%g_num)
#创建一把锁,这个锁默认是没有上锁的
mutex = threading.Lock()
t1 = threading.Thread(target = work1)
t1.start()
#t1.join()
t2 = threading.Thread(target = work2)
t2.start()
#t2.join()
多线程使用非共享变量
创建一个函数,多线程访问一个函数时,每个线程访问这个函数的变量值时独有的
通过线程名来判断
import threading
import time
def work1():
name = threading.current_thread().name #取线程名字比如 Thread-1 Main thread...
print("---thread name---%s"%name)
num = 0
if name == "Thread-1":
num += 1
else:
time.sleep(1)
print("thread name is %s---num is %d"%(name, num))
t1 = threading.Thread(target = work1)
t1.start()
#t1.join()
t2 = threading.Thread(target = work1)
t2.start()
#t2.join()
result:
---thread name---Thread-1
thread name is Thread-1---num is 1
---thread name---Thread-2
thread name is Thread-2---num is 0
死锁以及解决方法
加入超时时间:
注意acquire()这个上锁方法是阻塞的等在条件满足,不满足条件一直会卡在这里,下面就是一个死锁
class MyThread1(Thread):
def run(self):
if mutex1.acquire():
print("----------")
time.sleep(1)
if mutex2.acquire():
print("**********")
mutex2.release()
class MyThread2(Thread):
def run(self):
if mutex2.acquire():
print("###############")
time.sleep(1)
if mutex1.acquire():
print("$$$$$$$$$$")
mutex1.release()
if __name__ == "__main__":
mutex1 = Lock()
mutex2 = Lock()
t1 = MyThread1()
t2 = MyThread2()
t1.start()
t2.start()
result:
----------
###############
mutex.acquire(2)###2s之后还不能上锁的化,就继续往下走
同步的理解与应用
代码按照一定规律去执行, 不然很难保证task1 task2 task3依次输出
按照规定的先后顺序执行
import threading
import time
class Task1(threading.Thread):
def run(self):
while True:
if lock1.acquire():
print("----Task1----")
time.sleep(1)
lock2.release()
class Task2(threading.Thread):
def run(self):
while True:
if lock2.acquire():
print("----Task2----")
time.sleep(1)
lock3.release()
class Task3(threading.Thread):
def run(self):
while True:
if lock3.acquire():
print("----Task3----")
time.sleep(1)
lock1.release()
if __name__ == "__main__":
lock1 = threading.Lock()
lock2 = threading.Lock()
lock2.acquire()
lock3 = threading.Lock()
lock3.acquire()
t1 = Task1()
t2 = Task2()
t3 = Task3()
t1.start()
t2.start()
t3.start()
result:
----Task1----
----Task2----
----Task3----
----Task1----
----Task2----
----Task3----
----Task1----
----Task2----
....
![](https://img2020.cnblogs.com/blog/1087191/202108/1087191-20210830202349719-1663657721.png)
异步: 就是不确定哪一个先执行