python学习----线程、协程

多线程

线程模块

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()
发布了21 篇原创文章 · 获赞 3 · 访问量 977

猜你喜欢

转载自blog.csdn.net/weixin_46097280/article/details/104162399
今日推荐