Python Day09
一、进程与线程
1.什么是进程(process)?
二、线程
1.直接调用
1 import threading 2 import time 3 4 def run(x): 5 print("task:", x) 6 time.sleep(2) 7 8 t1 = threading.Thread(target=run, args=("t1",)) 9 t2 = threading.Thread(target=run, args=("t2",)) 10 t1.start() 11 t2.start()
1 import threading 2 import time 3 4 class MyThread(threading.Thread): 5 6 def __init__(self, n): 7 super(MyThread, self).__init__() 8 self.n = n 9 10 def run(self): 11 print("running task:", self.n) 12 time.sleep(2) 13 14 t1 = MyThread("t1") 15 t2 = MyThread("t2") 16 t1.start() 17 t2.start()
2.1join等待线程执行完毕
1 import threading 2 import time 3 4 def run(x): 5 print("running task:", x, threading.active_count()) 6 time.sleep(2) 7 print("task%s done" % x, threading.current_thread()) 8 9 start_time = time.time() 10 t_objs = [] 11 for i in range(50): 12 t = threading.Thread(target=run, args=("t%s" % i,)) 13 t.start() 14 t_objs.append(t) 15 16 for t in t_objs: 17 t.join() 18 19 print("all threads done", threading.current_thread(), threading.active_count()) 20 print("cost:", time.time() - start_time)
1 import threading 2 import time 3 4 def run(x): 5 print("running task:", x, threading.active_count()) 6 time.sleep(2) 7 print("task%s done" % x, threading.current_thread()) 8 9 start_time = time.time() 10 t_objs = [] 11 for i in range(50): 12 t = threading.Thread(target=run, args=("t%s" % i,)) 13 t.setDaemon(True) # 把当前线程设置为守护线程 14 t.start() 15 t_objs.append(t) 16 17 print("all threads done", threading.current_thread(), threading.active_count()) 18 print("cost:", time.time() - start_time)
1 import threading 2 import time 3 4 def change(): 5 lock.acquire() # 加锁 6 global num 7 num += 1 # 加锁和释放锁之间要保证快速计算,避免占着茅坑不拉屎现象 8 lock.release() # 释放锁 9 time.sleep(1) 10 11 num = 0 12 lock = threading.Lock() # 获取一把锁 13 14 for i in range(50): 15 t = threading.Thread(target=change) 16 t.start() 17 18 print(num)
为什么Python有GIL了,还需要互斥锁呢?这两个是不一样的,下面的图可以解释:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import threading 2 3 def run1(): 4 print("grab the first part data") 5 lock.acquire() 6 global num 7 num += 1 8 lock.release() 9 return num 10 11 def run2(): 12 print("grab the second part data") 13 lock.acquire() 14 global num2 15 num2 += 1 16 lock.release() 17 return num2 18 19 def run3(): 20 lock.acquire() 21 res = run1() 22 print('--------between run1 and run2-----') 23 res2 = run2() 24 lock.release() 25 print(res, res2) 26 27 if __name__ == '__main__': 28 29 num, num2 = 0, 0 30 lock = threading.RLock() 31 for i in range(10): 32 t = threading.Thread(target=run3) 33 t.start() 34 35 while threading.active_count() != 1: 36 print(threading.active_count()) 37 else: 38 print('----all threads done---') 39 print(num, num2)
1 import threading 2 import time 3 4 def run(n): 5 semaphore.acquire() 6 time.sleep(1) 7 print("run the thread: %s\n" % n) 8 semaphore.release() 9 10 if __name__ == '__main__': 11 12 semaphore = threading.BoundedSemaphore(5) # 最多允许5个线程同时运行 13 for i in range(20): 14 t = threading.Thread(target=run, args=(i,)) 15 t.start() 16 17 while threading.active_count() != 1: 18 pass # print threading.active_count() 19 else: 20 print('----all threads done---')
1 def hello(): 2 print("hello, world") 3 4 t = Timer(30.0, hello) 5 t.start() # after 30 seconds, "hello, world" will be printed
1 import time 2 import threading 3 4 event = threading.Event() 5 6 def lighter(): 7 count = 0 8 event.set() 9 while True: 10 if count <= 4: 11 print("\033[42;1m绿灯\033[0m") 12 elif 4 < count <= 9: 13 event.clear() 14 print("\033[41;1m红灯\033[0m") 15 elif count > 9: 16 event.set() 17 print("\033[42;1m绿灯\033[0m") 18 count = 0 19 time.sleep(1) 20 count += 1 21 22 def car(name): 23 while True: 24 if event.is_set(): 25 print("[%s] is running" % name) 26 time.sleep(1) 27 else: 28 print("\033[31;1m红灯亮了\033[0m") 29 print("[%s] is waiting" % name) 30 event.wait() 31 32 l = threading.Thread(target=lighter) 33 l.start() 34 car1 = threading.Thread(target=car, args=("Tesla",)) 35 car1.start()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import queue 2 3 q = queue.Queue() 4 q.put(1) 5 q.put(2) 6 q.put(3) 7 8 while True: 9 if q.qsize() == 0: 10 break 11 print(q.get()) 12 13 print("".center(50, "=")) 14 15 q = queue.LifoQueue() 16 q.put(1) 17 q.put(2) 18 q.put(3) 19 20 while True: 21 if q.qsize() == 0: 22 break 23 print(q.get()) 24 25 print("".center(50, "=")) 26 27 q = queue.PriorityQueue() 28 q.put((2, "Profhua")) 29 q.put((1, "Breakering")) 30 q.put((3, "Wolf")) 31 32 while True: 33 if q.qsize() == 0: 34 break 35 print(q.get())
1 import time 2 import queue 3 import threading 4 q = queue.Queue(maxsize=10) 5 6 def producer(name): 7 count = 1 8 while True: 9 q.put("骨头%s" % count) 10 print("%s生产了骨头" % name, count) 11 count += 1 12 time.sleep(0.1) 13 14 def consumer(name): 15 while True: 16 if q.qsize() > 0: 17 print("%s 正在吃 %s" % (name, q.get())) 18 time.sleep(1) 19 20 p = threading.Thread(target=producer, args=("Breakering",)) 21 c = threading.Thread(target=consumer, args=("Dog",)) 22 c1 = threading.Thread(target=consumer, args=("Dog1",)) 23 24 p.start() 25 c.start() 26 c1.start()
三、进程
1.介绍
multiprocessing
is a package that supports spawning processes using an API similar to the threading
module. The multiprocessing
package offers both local and remote(远程的) concurrency(并发), effectively(有效) side-stepping(绕过,PS:猜测) the Global Interpreter Lock (全局解释器锁) by using subprocesses instead of threads. Due to this, the multiprocessing
module allows the programmer to fully leverage(利用) multiple processors on a given machine. It runs on both Unix and Windows.1 import multiprocessing 2 import time 3 4 def run(x): 5 print("task:", x) 6 time.sleep(2) 7 8 if __name__ == '__main__': 9 for i in range(10): # 启动了10个进程 10 t = multiprocessing.Process(target=run, args=(i,)) 11 t.start()
To show the individual process IDs involved, here is an expanded example:
1 from multiprocessing import Process 2 import os 3 4 def info(title): 5 print(title) 6 print('module name:', __name__) 7 print('parent process:', os.getppid()) 8 print('process id:', os.getpid()) 9 print("\n\n") 10 11 def f(name): 12 info('\033[31;1mfunction f\033[0m') 13 print('hello', name) 14 15 if __name__ == '__main__': 16 info('\033[32;1mmain process line\033[0m') 17 p = Process(target=f, args=('bob',)) 18 p.start() 19 p.join()
注:子进程都是由父进程创建的
1 from multiprocessing import Process, Queue 2 3 def f(q): 4 q.put([1, "a", "A"]) 5 6 if __name__ == '__main__': 7 q = Queue() 8 p = Process(target=f, args=(q,)) 9 p.start() 10 p.join() 11 print(q.get())
Pipes
The Pipe()
function returns a pair of(一对) connection objects connected by a pipe which by default is duplex (two-way). For example:
1 from multiprocessing import Process, Pipe 2 3 def f(conn): 4 conn.send([42, None, 'hello from child']) 5 conn.send([42, None, 'hello from child2']) 6 print("from parent:", conn.recv()) 7 conn.close() 8 9 if __name__ == '__main__': 10 parent_conn, child_conn = Pipe() 11 p = Process(target=f, args=(child_conn,)) 12 p.start() 13 print(parent_conn.recv()) # prints "[42, None, 'hello']" 14 print(parent_conn.recv()) # prints "[42, None, 'hello']" 15 parent_conn.send("张洋可好") # prints "[42, None, 'hello']" 16 p.join()
The two connection objects returned by Pipe()
represent the two ends of the pipe. Each connection object has send()
and recv()
methods (among others). Note that data in a pipe may become corrupted if two processes (or threads) try to read from or write to the same end of the pipe at the same time. Of course there is no risk of corruption from processes using different ends of the pipe at the same time.
注:这句话就是管道对象返回两个端口,如果同时读取和写入管道的同一端,则管道的数据可能会损坏。当然,同时使用管道的不同端口是不会有任何风险的。
Manager()
controls a server process which holds Python objects and allows other processes to manipulate(操纵) them using proxies(代理).Manager()
will support types list
, dict
, Namespace
, Lock
, RLock
, Semaphore
, BoundedSemaphore
, Condition
, Event
, Barrier
, Queue
, Value
and Array
. For example:1 from multiprocessing import Process, Manager 2 import os 3 4 def f(d, l): 5 d[os.getpid()] =os.getpid() 6 l.append(os.getpid()) 7 print(l) 8 9 if __name__ == '__main__': 10 with Manager() as manager: 11 d = manager.dict() # {} # 生成一个字典,可在多个进程间共享和传递 12 13 l = manager.list(range(5)) # 生成一个列表,可在多个进程间共享和传递 14 p_list = [] 15 for i in range(10): 16 p = Process(target=f, args=(d, l)) 17 p.start() 18 p_list.append(p) 19 for res in p_list: # 等待结果 20 res.join() 21 22 print(d) 23 print(l)
1 from multiprocessing import Process, Lock 2 3 def f(l, i): 4 l.acquire() # 锁上 5 print('hello world', i) 6 l.release() # 释放锁 7 8 if __name__ == '__main__': 9 lock = Lock() # 生成一个锁 10 11 for num in range(100): 12 Process(target=f, args=(lock, num)).start()
- apply
- apply_async
1 from multiprocessing import Process, Pool 2 import time 3 import os 4 5 def Foo(i): 6 time.sleep(2) 7 print("in process", os.getpid()) 8 return i + 100 9 10 def Bar(arg): 11 print('-->exec done:', arg, os.getpid()) 12 13 if __name__ == '__main__': 14 # freeze_support() 15 pool = Pool(processes=3) # 允许进程池同时放入5个进程 16 print("主进程", os.getpid()) 17 for i in range(10): 18 pool.apply_async(func=Foo, args=(i,), callback=Bar) # callback=回调 19 # pool.apply(func=Foo, args=(i,)) #串行 20 # pool.apply_async(func=Foo, args=(i,)) #串行 21 print('end') 22 pool.close() 23 pool.join() # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。.join()
四、总结
- 线程是执行的指令集,进程是资源的集合;
- 线程的启动速度要比进程的启动速度要快;
- 两个线程的执行速度是一样的;
- 进程与线程的运行速度是没有可比性的;
- 线程共享创建它的进程的内存空间,进程的内存是独立的;
- 两个线程共享的数据都是同一份数据,两个子进程的数据不是共享的,而且数据是独立的;
- 同一个进程的线程之间可以直接交流,同一个主进程的多个子进程之间是不可以进行交流,如果两个进程之间需要通信,就必须要通过一个中间代理来实现;
- 一个新的线程很容易被创建,一个新的进程创建需要对父进程进行一次克隆;
- 一个线程可以控制和操作同一个进程里的其他线程,线程与线程之间没有隶属关系,但是进程只能操作子进程;
- 改变主线程,有可能会影响到其他线程的行为,但是对于父进程的修改是不会影响子进程。