#线程的创建
from threading import Thread
import time
def func(name):
time.sleep(1)
print(f'{name} say hello')
if __name__ == '__main__':
t = Thread(target=func,args=('tom',))
t. start()
print('主线程')
#主线程 很快就打印出来,过了不到1s 才打印tom say hello
#线程的开启很快,线程有没有join?
#线程join
from threading import Thread,enumerate as en
import time
def func(name):
time.sleep(1)
print(f'{name} say hello')
if __name__ == '__main__':
t = Thread(target=func,args=('tom',))
t. start()
print(en()) #先打印2个正在执行的线程 threading 里的enumerate 用于罗列当前存活的线程
t.join()
print(en()) #现在打印只有1个主线程存活MainThread
print('主线程') #join了以后 等待线程结束才执行主线程
# [<_MainThread(MainThread, started 13796)>, <Thread(Thread-1, started 13104)>]
# tom say hello
# [<_MainThread(MainThread, started 13796)>]
# 主线程.....
#用自定义类创建线程
from threading import Thread
import time
class MyThread(Thread):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
time.sleep(1)
print(f'{self.name} say hello')
if __name__ == '__main__':
t = MyThread('tom')#可以方便的传参,但是调用函数不够灵活,必须写在类的run方法中
t.start()
print('MainThread')
#同一个进程开启的线程拥有相同的进程id 和不同的线程id
from threading import Thread
from multiprocessing import Process
import os
def func():
print(os.getpid())
if __name__ == '__main__':
t1 = Thread(target=func)
t2 = Thread(target=func)
t1.start()
t2.start()
p1 = Process(target=func)
p2 = Process(target=func)
p1.start()
p2.start()
print(f'主进程id{os.getpid()}')
# 13476
# 13476
# 主进程id13476 (前面2个线程 和主进程的进程id 一致)
# 3352
# 13452 (后面2个进程id不同而且与主进程进程id不同)
#开启子进程和子线程效率对比
from threading import Thread
from multiprocessing import Process
import os
def func():
print(os.getpid())
if __name__ == '__main__':
p1 = Process(target=func)
p1.start() #虽然是先开启的子进程,但是还是子线程先打印了结果
t1 = Thread(target=func)
t1.start()
p1.join()
t1.join()
print(f'主进程id是:{os.getpid()}')
# 12636 (这是子线程的打印,因为子线程所在进程id和主线程所在进程id一致)
# 12104 (这是子进程id)
# 主进程id是:12636
#子线程共享主进程数据
from threading import Thread
n=1
def func():
global n
n=0
if __name__ == '__main__':
t1 = Thread(target=func)
t1.start()
t1.join()
print('主进程的n:',n) #主进程的n: 0
#多线程实现socket
#server端
from threading import Thread
import socket
def func(conn):
while 1: #这里while 是可以循环聊天
msg = conn.recv(1024).decode('utf-8')
conn.send(msg.upper().encode('utf-8'))
conn.close()
if __name__ == '__main__':
sk = socket.socket()
sk.bind(('127.0.0.1', 9002))
sk.listen()
while 1: #这里while 是接收多个客户端连接
conn,addr= sk.accept()
t = Thread(target=func,args=(conn,))
t.start()
sk.close()
#client端
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 9002))
while 1:
msg = input('>>>')
sk.send(msg.encode('utf-8'))
msg = sk.recv(1024).decode('utf-8')
print(msg)
sk.close()
#获取当前代码所在线程的线程名
from threading import Thread
import threading
from multiprocessing import Process
import time
def func():
time.sleep(1)
print(threading.current_thread().getName()) #先打印线程名 :Thread-1,这里的current_thread是可以获取当前代码所在的线程,返回线程对象
if __name__ == '__main__':
t = Thread(target=func)
t.start()
t.join()
print(threading.current_thread().getName()) #线程结束打印主线程名
print(threading.current_thread()) #打印当前代码所在线程
print(threading.enumerate()) #打印所有线程,列表,只剩下主线程了
print(threading.active_count())#打印活动的线程个数,只有主线程了
# Thread-1
# MainThread
# <_MainThread(MainThread, started 5740)>
# [<_MainThread(MainThread, started 5740)>]
# 1
#线程的is_alive方法和 join方法
import threading
import time
def func():
time.sleep(1)
if __name__ == '__main__':
t = threading.Thread(target=func)
t.start()
print(t.is_alive()) #True is_alive 判断线程是否存活
t.join() #join 等子线程结束再执行主线程代码
print('主线程')
print(t.is_alive()) #False
#守护线程的设置 setDaemon(True)
from threading import Thread
import time
def func():
time.sleep(1)
print('hello')
if __name__ == '__main__':
t = Thread(target=func)
t.setDaemon(True) #守护线程必须在启动之前设置
t.start()
print('主线程') #结果就没有打印hello ,只打印了‘主线程’ 守护线程被强制停止了
#如果把t.setDaemon(True)注释掉,不设置守护线程,结果就是先打印‘主线程’,再打印‘hello’,主进程等守护线程也结束才回收了资源
#如果设置2个线程对比一下看时间
from threading import Thread
import time
def func():
time.sleep(3)
print('hello1')
def func2():
time.sleep(1)
print('hello2')
if __name__ == '__main__':
t = Thread(target=func) #func 被安排到守护线程里,sleep的比较久,结果并没有执行,还是在
t.setDaemon(True)
t.start()
t2 = Thread(target=func2)
t2.start()
print('主线程')
# 主线程
# hello2
#这里func被安排了守护线程,先执行了主线程,然后打印非守护线程,最后守护线程sleep 了 3s没等结束 整个进程就结束了
#线程是否也会抢占资源?
from threading import Thread
import time
def func():
global n
temp = n
time.sleep(0.001) #这里sleep的时候 100个线程已经开始了,每个线程里 temp取到的值都是100,线程的开启很快,如果这里写成了0.001s ,结果变成95
n = temp - 1 #最后对n做了100次的赋值,赋值成了99
if __name__ == '__main__':
n = 100
t_list = []
for i in range(100):
t = Thread(target=func)
t_list.append(t)
t.start()
for t in t_list:
t.join()
print(n) #99
#结果居然是99,n被所有线程抢占了
#线程的加锁
from threading import Thread,Lock
import time
def func(lock):
time.sleep(1)
with lock:
global n
temp = n
n = temp - 1
if __name__ == '__main__':
time1 = time.time()
lock = Lock()
n = 100
t_list = []
for i in range(100):
t = Thread(target=func,args=(lock,))
t_list.append(t)
t.start()
for t in t_list:
t.join()
time2 = time.time()
print(time2-time1,n) #0.060001373291015625 0
# 原来的并发执行,变成串行,牺牲执行效率保证数据安全
#如果每次开启一个线程t 都把它join一下,也是加锁的效果,但是结果
from threading import Thread,Lock
import time
def func(lock):
time.sleep(1)
with lock:
global n
temp = n
n = temp - 1
if __name__ == '__main__':
time1 = time.time()
lock = Lock()
n = 100
t_list = []
for i in range(100):
t = Thread(target=func,args=(lock,))
t_list.append(t)
t.start()
t.join()
time2 = time.time()
print(time2-time1,n) #100.91230297088623 0
#结果过了100s才打印出结果0,加锁有技巧,在各个线程可能出现抢占资源的代码处加锁,其他代码并行执行,缩短时间
#线程死锁
from threading import Lock as Lock
import time
mutexA=Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()
# mutexA 连续请求加锁了2次,资源都是打印123?还没弄清楚
#递归锁 Rlock ,这样就可以打印了
from threading import RLock as Lock
import time
mutexA=Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()
#科学家吃面,死锁,不懂?
import time
from threading import Thread,Lock
noodle_lock = Lock()
fork_lock = Lock()
def eat1(name):
noodle_lock.acquire()
print('%s 抢到了面条'%name)
fork_lock.acquire()
print('%s 抢到了叉子'%name)
print('%s 吃面'%name)
fork_lock.release()
noodle_lock.release()
def eat2(name):
fork_lock.acquire()
print('%s 抢到了叉子' % name)
time.sleep(1)
noodle_lock.acquire()
print('%s 抢到了面条' % name)
print('%s 吃面' % name)
noodle_lock.release()
fork_lock.release()
for name in ['哪吒','egon','yuan']:
t1 = Thread(target=eat1,args=(name,))
t2 = Thread(target=eat2,args=(name,))
t1.start()
t2.start()
#单例模式,大型翻车现场
import time
class singleton:
__instance = None
def __new__(cls, *args, **kwargs):
if not cls.__instance:
time.sleep(0.000001) #这里sleep了一段时间,模拟时间片到了
cls.__instance = super().__new__(cls)
return cls.__instance
def func():
a = singleton()
print(a) #打印对象结果
from threading import Thread
if __name__ == '__main__':
for i in range(10):
t = Thread(target=func)
t.start()
# <__main__.singleton object at 0x000001EDD08EA640>
# <__main__.singleton object at 0x000001EDD06AF340>
# <__main__.singleton object at 0x000001EDD06AF340>
# ....
#这里显示了两个不同的对象地址,说明不是单例了,单例模式也不安全了
#单例模式,加锁,外部传进来
class singleton:
__instance = None
def __new__(cls, *args, **kwargs):
with args[0]:
if not cls.__instance:
cls.__instance = super().__new__(cls)
return cls.__instance
def func(lock):
a = singleton(lock)
print(a)
from threading import Thread,Lock
if __name__ == '__main__':
lock = Lock()
for i in range(10):
t = Thread(target=func,args=(lock,))
t.start()
# <__main__.singleton object at 0x0000026C4200C730>
# <__main__.singleton object at 0x0000026C4200C730>
# <__main__.singleton object at 0x0000026C4200C730>
# 。。。
# 这样虽然能解决,但是传递了参数到单例类中,面向对象中能封装到类中的就可以不用参数传递
#单例模式,在单例对象中加锁
class singleton:
from threading import Lock
__instance = None
lock = Lock()
def __new__(cls, *args, **kwargs):
with cls.lock:
if not cls.__instance:
cls.__instance = super().__new__(cls)
return cls.__instance
def func():
a = singleton()
print(a)
from threading import Thread
if __name__ == '__main__':
for i in range(10):
t = Thread(target=func)
t.start()
# <__main__.singleton object at 0x000002A1EFF6B790>
# <__main__.singleton object at 0x000002A1EFF6B790>
# <__main__.singleton object at 0x000002A1EFF6B790>
# ......
#【记住】
#不操作全局变量,几乎不会出现线程安全问题,包括类里的静态变量
# += -= *= /= if while a=a.strip() split() 等数据不安全
# queue logging 数据安全
#dis 模块
import dis
def func():
a = 1
print(a)
print(dis.dis(func))
#显示该函数底层的实现
#递归锁RLock
#互斥锁只拿到一个钥匙,然后进去执行代码
#递归锁可以多次的拿钥匙,执行代码然后再挨个退出
#递归锁效率低
#互斥锁
from threading import Thread,Lock
def func(i,lock):
lock.acquire()
lock.acquire()
print(i)
lock.release()
lock.release()
if __name__ == '__main__':
lock = Lock()
for i in range(6):
t = Thread(target=func,args=(i,lock))
t.start()
#这里会停住,lock.acquire()上了2次锁,没有结果,就执行不下去了
#递归锁
from threading import Thread,RLock
def func(i,lock):
lock.acquire()
lock.acquire()
print(i)
lock.release()
lock.release()
if __name__ == '__main__':
lock = RLock()
for i in range(6):
t = Thread(target=func,args=(i,lock))
t.start()
#执行下去了,第一次 acquire 获得一次操作资源的权限,操作的是acquire 和最后一个release方法之间的代码(资源)
#层层执行,最后层层释放