多线程threading
多线程特点:
#线程的并发是利用cpu上下文的切换(是并发,不是并行)#多线程执行的顺序是无序的#多线程共享全局变量#线程是继承在进程里的,没有进程就没有线程#GIL全局解释器锁#只要在进行耗时的IO操作的时候,能释放GIL,所以只要在IO密集型的代码里,用多线程就很合适
# 无序的,并发的 def test1(n): time.sleep(1) print(‘task‘, n) for i in range(10): t = threading.Thread(target=test1,args=(‘t-%s‘ % i,)) t.start()
#计算并发所用的时间 import threading import time def test1(n): time.sleep(1) print(‘task‘, n) def test2(n): time.sleep(1) print(‘task‘, n) start = time.time() l = [] t1 = threading.Thread(target=test1, args=(1,)) t2 = threading.Thread(target=test1, args=(2,)) t1.start() t2.start() l.append(t1) l.append(t2) for i in l: i.join() end = time.time() print(end - start)
GIL的全称是:Global Interpreter Lock,意思就是全局解释器锁,这个GIL并不是python的特性,他是只在Cpython解释器里引入的一个概念,而在其他的语言编写的解释器里就没有这个GIL例如:Jython,Pypy
为什么会有gil?:
随着电脑多核cpu的出现核cpu频率的提升,为了充分利用多核处理器,进行多线程的编程方式更为普及,随之而来的困难是线程之间数据的一致性和状态同步,而python也利用了多核,所以也逃不开这个困难,为了解决这个数据不能同步的问题,设计了gil全局解释器锁。
说到gil解释器锁,我们容易想到在多线程中共享全局变量的时候会有线程对全局变量进行的资源竞争,会对全局变量的修改产生不是我们想要的结果,而那个时候我们用到的是python中线程模块里面的互斥锁,哪样的话每次对全局变量进行操作的时候,只有一个线程能够拿到这个全局变量;看下面的代码:
import threading global_num = 0 def test1(): global global_num for i in range(1000000): global_num += 1 print("test1", global_num) def test2(): global global_num for i in range(1000000): global_num += 1 print("test2", global_num) t1 = threading.Thread(target=test1) t2 = threading.Thread(target=test2) t1.start() t2.start() 在上面的例子里,我们创建了两个线程来争夺对global_num的加一操作,但是结果并非我们想要的,所以我们在这里加入了互斥锁 import threading import time global_num = 0 lock = threading.Lock() def test1(): global global_num lock.acquire() for i in range(1000000): global_num += 1 lock.release() print("test1", global_num) def test2(): global global_num lock.acquire() for i in range(1000000): global_num += 1 lock.release() print("test2", global_num) t1 = threading.Thread(target=test1) t2 = threading.Thread(target=test2) start_time = time.time() t1.start() t2.start()
多进程multiprocessing
#一个程序运行起来之后,代码+用到的资源称之为进程,它是操作系统分配资源的基本单位,不仅可以通过线程完成多任务,进程也是可以的
#进程之间是相互独立的
#cpu密集的时候适合用多进程
#进程之间不共享 import multiprocessing from multiprocessing import Pool import time import threading g_num = 0 def edit(): global g_num for i in range(10): g_num += 1 def reader(): print(g_num) if __name__ == ‘__main__‘: p1 = multiprocessing.Process(target=edit) p2 = multiprocessing.Process(target=reader()) p1.start() p2.start() p1.join() p2.join()
#多进程并发 import multiprocessing from multiprocessing import Pool import time def test1(): for i in range(10): time.sleep(1) print(‘test‘, i) def test2(): for i in range(10): time.sleep(1) print(‘test‘, i) if __name__ == ‘__main__‘: p1 = multiprocessing.Process(target=test1) p2 = multiprocessing.Process(target=test2) p1.start() p2.start()
#进程池 import multiprocessing from multiprocessing import Pool import time import threading g_num = 0 def test1(n): for i in range(n): time.sleep(1) print(‘test1‘, i) def test2(n): for i in range(n): time.sleep(1) print(‘test2‘, i) def test3(n): for i in range(n): time.sleep(1) print(‘test3‘, i) def test4(n): for i in range(n): time.sleep(1) print(‘test4‘, i) if __name__ == ‘__main__‘: pool = Pool(3)#把进程声明出来括号里不写东西说明无限制,如果写数字,就是最大的进程数 pool.apply_async(test1,(10,))#用pool去调用函数test1,参数为10格式为(10,) pool.apply_async(test2,(10,))#用pool去调用函数test2,参数为10格式为(10,) pool.apply_async(test3,(10,))#用pool去调用函数test3,参数为10格式为(10,) pool.apply_async(test4,(10,))#用pool去调用函数test4,参数为10格式为(10,) pool.close()#close必须在join的前面 pool.join()
协程并发(gevent)
# 异步IO# 进程是资源分配的单位 # 线程是操作系统调度的单位 # 进程切换需要的资源最大,效率低 # 线程切换需要的资源一般,效率一般 # 协程切换任务资源很小,效率高 # 多进程、多线程根据cpu核数不一样可能是并行的,但是协成在一个线程中
#协程,自动切换 import gevent,time from gevent import monkey monkey.patch_all() def test1(): for i in range(10): time.sleep(1) print(‘test1‘, 1) def test2(): for i in range(10): time.sleep(2) print(‘test2‘, 1) g1 = gevent.spawn(test1) g2 = gevent.spawn(test2) g1.join() #开启 g2.join()
#server端 import gevent from gevent import socket, monkey monkey.patch_all() def server_recv_conn(port): s = socket.socket() s.bind((‘0.0.0.0‘, port)) s.listen(200) while True: conn, addr = s.accept() g = gevent.spawn(recv_request, conn) g.join() def recv_request(conn): while True: data = conn.recv(1024) data = data.decode(‘utf-8‘) print("recv:", data) conn.send(data.upper().encode(‘utf-8‘)) if __name__ == ‘__main__‘: server_recv_conn(8888) #client端 import socket HOST = ‘localhost‘ PORT = 8888 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) while True: msg = input("==>:") s.send(msg.encode(‘utf-8‘)) data = s.recv(1024) print(‘接收:‘, data.decode(‘utf-8‘)) s.close()
原文地址:https://www.cnblogs.com/zhou2019/p/10599204.html
时间: 2024-11-13 06:55:12