多线程
线程模块
from threading import Thread
from multiprocessing import Process
import os
import time
def work():
print("hello",os.getpid()) #获取⽬前的进程id
pass
def main():
#定义两个线程
t1 = Thread(target=work)
t2 = Thread(target=work)
t1.start()
t2.start()
print('主线程/进程pid',os.getpid())
#定义两个就进程
p1 = Process(target=work)
p2 = Process(target=work)
p1.start()
p2.start()
pass
if __name__ == '__main__':
main()
from threading import Thread
from multiprocessing import Process
import os
import time
def work():
global n
n = 0
pass
def main():
'''
n = 100
p = Process(target=work) #这⾥⾯的n是0,但是⽗进程依然是100
p.start()
p.join()
print('主',n)
'''
n = 1
t = Thread(target=work)
t.start()
t.join()
print('主',n) #线程是共享数据的
pass
if __name__ == '__main__':
main()
from threading import Thread
import threading
from multiprocessing import Process
import os
def work():
import time
time.sleep(3)
print(threading.current_thread().getName())#获取线程名字
pass
def main():
#在主线程下开下线程
t1 = Thread(target=work)
t1.start()
t2 = Thread(target=work)
t2.start()
print(threading.current_thread().getName()) #主线程的名字
print(threading.enumerate()) #有谁还在运⾏
print(threading.active_count()) #⼀共多少个线程在运⾏
pass
if __name__ == '__main__':
main()
from threading import Thread
import threading
from multiprocessing import Process
import os
import time
def sayhi(name):
time.sleep(2)
print("%s say hello" %name)
pass
def main():
t = Thread(target=sayhi,args=('xiaohong',))
t.start()
t.join()
print("main")
print(t.is_alive()) #是否存活
pass
if __name__ == '__main__':
main()
守护线程
守护xx会等主xx运⾏完毕之后被销毁!!!
运⾏完毕并⾮终⽌运⾏!!!!!!!!
from threading import Thread
import threading
from multiprocessing import Process
import os
import time
def foo():
print(123)
time.sleep(1)
print('end123')
pass
def bar():
print(456)
time.sleep(3)
print('end456')
pass
def main():
t1 = Thread(target=foo)
t2 = Thread(target=bar)
t1.daemon = True
t2.daemon = True
t1.start()
t2.start()
print('main')
pass
if __name__ == '__main__':
main()
同步锁
from threading import Thread,Lock
import time
def work(lock):
global n
n = 100
lock.acquire() #上锁,其他⼈不能动这个数据(虽然他们内存共享)
temp = n
time.sleep(0.1)
n = temp-1
lock.release() #解锁,下⼀个⼈可以⽤这个数据
pass
def main():
lock = Lock()
l = []
for i in range(100):
p = Thread(target=work,args=(lock,))
l.append(p)
p.start()
for p in l:
p.join()
print(n)
pass
if __name__ == '__main__':
main()
from threading import Thread,Lock
import time
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()
pass
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()
pass
def main():
for name in ['顾客1','顾客2','顾客3']:
t1 = Thread(target=eat1,args=(name,))
t2 = Thread(target=eat2,args=(name,))
t1.start()
t2.start()
pass
if __name__ == '__main__':
main()
卡住,有的⼈只抢到了叉⼦有的⼈只抢到了⾯条
递归锁
RLock⾥维护了⼀个Lock的⼀个counter变量,counter记录着acquire的次数,就可以让资源可以被多次acquire,直到⼀个进程所有的acquire都被release,其他进程才能获得资源。
from threading import Thread,RLock
import time
noodle_lock = fork_lock = RLock() #递归锁⼀起定义
def eat1(name):
noodle_lock.acquire()
print('%s 抢到了⾯条'%name)
fork_lock.acquire()
print('%s 抢到了叉⼦'%name)
print('%s 吃⾯'%name)
fork_lock.release()
noodle_lock.release()
pass
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()
pass
def main():
for name in ['顾客1','顾客2','顾客3']:
t1 = Thread(target=eat1,args=(name,))
t2 = Thread(target=eat2,args=(name,))
t1.start()
t2.start()
pass
if __name__ == '__main__':
main()
线程队列
import queue
def main():
#线程队列,先进先出
q = queue.Queue()
q.put('first')
q.put('second')
q.put('third')
print(q.get())
print(q.get())
print(q.get())
pass
def main():
#后进先出
q = queue.LifoQueue()
q.put('first')
q.put('second')
q.put('third')
print(q.get())
print(q.get())
print(q.get())
pass
def main():
#优先级队列,越⼩越优先
q = queue.PriorityQueue()
q.put((20,'a'))
q.put((10,'b'))
q.put((30,'c'))
print(q.get())
print(q.get())
print(q.get())
pass
协程
进程是资源分配的最小单位
线程是cpu调度的最小单位
进程和线程在创建的时候都需要消耗时间,还需要管理他们之间的切换
所有人的目的都是实现并发处理事情
使用单线程单进程完成并发处理
def create_num(all_num):
print("--1--")
a,b = 0,1
current_num = 0
while current_num < all_num:
print("--2--")
ret = yield a
print("---ret---",ret)
print("--3--")
a,b = b , a+b
current_num+=1
print("--4--")
pass
def main():
obj = create_num(10)
ret = next(obj)
print(ret)
ret = obj.send("haha")
print(ret)
pass
if __name__ == '__main__':
main()
import time
def task_1():
while True:
print("--1--")
time.sleep(1)
yield
pass
def task_2():
while True:
print("--2--")
time.sleep(2)
yield
pass
def main():
t1 = task_1()
t2 = task_2()
while True:
next(t1)
next(t2)
pass
if __name__ == '__main__':
main()
协程是可以用户自己调度的,是一个轻量级线程
单线程内开启协程,如果碰到了input,output,就会从应用程序这个级别进行切换
所以协程开销很小,属于程序级别的切换,操作系统感知不到,所以协程是真的轻量级
单线程内实现最大的并发效果,最大程度利用cpu
但是协程本质是单线程的,无法利用多核,所以可以考虑一个程序开多个进程,一个进程开多个线程,每个线程开协程
一般协程指单个线程,一旦协程出现了阻塞,就会整个程序阻塞
修改共享的数据不要加锁
import time
from greenlet import greenlet
def f1():
res = 1
for i in range(10000000):
res +=1
time.sleep(1)
print(res)
g2.switch()
pass
def f2():
res = 1
for i in range(20000000):
res +=2
time.sleep(1)
print(res)
g1.switch() #此时这个函数的结果凝固,切换到另一个地方
pass
start = time.time()
g1 = greenlet(f1)
g2 = greenlet(f2)
g2.switch() #先开始谁
stop = time.time()
print(stop-start) #1.624s
import time
from greenlet import greenlet
def f1(g2,g1):
res = 1
for i in range(10000000):
res +=1
time.sleep(1)
print(res)
g2.switch(g1,g2)
pass
def f2(g1,g2):
res = 1
for i in range(20000000):
res +=2
time.sleep(1)
print(res)
g1.switch(g2,g1)
pass
def main():
start = time.time()
g1 = greenlet(f1)
g2 = greenlet(f2)
g2.switch(g1,g2)
stop = time.time()
print(stop - start) # 如果不用greenlet是1.624s,如果用就5s多,并没有解决效率的问题
pass
if __name__ == '__main__':
main()
因为greenlet没法解决效率问题,所以用gevent,gevent可以以后用来当协程池,是对greenlet的一个封装
如果不打补丁,就要用gevent.sleep(1) #模拟io阻塞,如果不用模拟io阻塞又不打补丁,就是正常执行规律
from gevent import monkey;monkey.patch_all() #打补丁
import gevent,time
def eat(name):
print("%s eat 1"%name)
#gevent.sleep(1) #模拟io阻塞
time.sleep(1)
print("%s eat 2" % name)
pass
def play(name):
print("%s play 1"%name)
#gevent.sleep(1)
time.sleep(2)
print("%s play 2" % name)
pass
def main():
g1 = gevent.spawn(eat,'xiaoming')
g2 = gevent.spawn(play,'xiaohong')
#g1.join()
#g2.join()
gevent.joinall([g1,g2])
print("main")
pass
if __name__ == '__main__':
main()
协程实际上不是线程,所以打印出来的是假线程
from gevent import monkey;monkey.patch_all() #打补丁
import threading
import gevent,time
def eat(name):
print(threading.current_thread().getName())#显示假线程!!!
print("%s eat 1"%name)
#gevent.sleep(1) #模拟io阻塞
time.sleep(1)
print("%s eat 2" % name)
pass
def play(name):
print(threading.current_thread().getName())
print("%s play 1"%name)
#gevent.sleep(1)
time.sleep(2)
print("%s play 2" % name)
pass
def main():
g1 = gevent.spawn(eat,'xiaoming')
g2 = gevent.spawn(play,'xiaohong')
#g1.join()
#g2.join()
gevent.joinall([g1,g2])
print("main")
pass
if __name__ == '__main__':
main()
使用协程实现高效率
rom gevent import spawn,joinall,monkey;monkey.patch_all() #打补丁
import time
def task(pid):
time.sleep(0.5)
print("task %s done"%pid)
pass
#同步
def sync():
for i in range(10):
task(i)
pass
#异步
def asynch():
g_1 = [spawn(task,i) for i in range(10)]
joinall(g_1)
print('done')
pass
def main():
#sync() #按流程去做
asynch() #使用协程创建假线程最快速度完成
pass
if __name__ == '__main__':
main()