线程和进程的区别:
- Threads share the address space of the process that created it; processes have their own address space.
- Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
- Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
- New threads are easily created; new processes require duplication of the parent process.
- Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
- Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
线程共享创建它的进程的地址空间;进程有自己的地址空间。
线程直接访问进程的数据段;进程拥有父进程的数据段的自身副本。
线程可以直接通信和该进程内的其他线程。 进程之间的通信必须通过 专有的进程间通信方式。
新线程很容易被创建;新进程需要复制父进程。
线程可以对相同进程的其他的线程进行直接的控制;进程只能对子进程进行控制。
对主线程的更改(取消、优先级更改等)可能影响进程的其他线程的行为;对父进程的更改不会影响子进程。
Python threading模块
线程之间不关联,子线程启动后,默认主线程接着往下走不会等待子线程:
import threading,time def run(n): print(‘task‘,n) time.sleep(3) print("task done") start_time = time.time() for i in range(10): t1=threading.Thread(target=run,args=(i,)) t1.start() print("finished") #主线程不会等待子线程全部执行完在打印 print("cost is ",time.time()-start_time)
执行结果:
task 0
task 1
task 2
task 3
task 4
task 5
task 6
task 7
task 8
task 9
finished
cost is 0.002000093460083008
task done
task done
task done
task done
task done
task done
task done
task done
task done
task done
如何实现子线程执行完在接着往下走呢? 加入join后,子线程一个一个的执行,实现串行的效果 。join相当于是wait
import threading,time def run(n): print(‘task‘,n) time.sleep(3) print("task done") start_time = time.time() for i in range(10): t1=threading.Thread(target=run,args=(i,)) t1.start() t1.join() #wait print("finished") print("cost is ",time.time()-start_time)
执行结果:
task 0
task done
task 1
task done
task 2
task done
task 3
task done
task 4
task done
task 5
task done
task 6
task done
task 7
task done
task 8
task done
task 9
task done
finished
cost is 30.00371479988098
如何实现并行执行10个线程,最后统计执行的时间
import threading,time def run(n): print(‘task‘,n) time.sleep(3) print("task done") start_time = time.time() task_list = [] for i in range(10): t1=threading.Thread(target=run,args=(i,)) t1.start() task_list.append(t1) #实现了线程启动不阻塞 for j in task_list : j.join() #等待所有线程执行后,主线程才接着往下走 print("finished") print("cost is ",time.time()-start_time) 执行结果: task 0 task 1 task 2 task 3 task 4 task 5 task 6 task 7 task 8 task 9 task done task done task done task done task done task done task done task done task done task done finished cost is 3.012172222137451
设置守护线程:程序在非守护线程执行完毕就退出
import threading,time def run(n): print(‘task‘,n) time.sleep(3) print("task done") start_time = time.time() task_list = [] for i in range(10): t1=threading.Thread(target=run,args=(i,)) t1.setDaemon(True) #每个子线程都设置为守护线程,主线程退出程序即退出,子线程跟着中断,不等子线程执行完 t1.start() task_list.append(t1) #for j in task_list : # j.join() print("finished") print("cost is ",time.time()-start_time) 执行结果: task 0 task 1 task 2 task 3 task 4 task 5 task 6 task 7 task 8 task 9 finished cost is 0.0030002593994140625
Python GIL(Global Interpreter Lock)
CPython是大部分环境下默认的Python执行环境。在CPython解释器下,无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行。
子线程之间的通信:
import threading,time num = 0 def run(n): global num print ‘task‘,n num +=1 time.sleep(0.3) print "task done" start_time = time.time() task_list = [] for i in range(100000): t1=threading.Thread(target=run,args=(i,)) t1.start() task_list.append(t1) for j in task_list : j.join() print num 在python2.6 执行: 99982 # why
在python3.x 执行时不会出错
*注:不要在3.x上运行,不知为什么,3.x上的结果总是正确的,可能是自动加了锁
结果为99982 而不是 100000.
如何保证计算不出错? 在修改数据时加锁,在修改数据时让程序串行 。同时让其他操作并行
GIL VS Lock
Python已经有一个GIL来保证同一时间只能有一个线程来执行了,为什么这里还需要lock? 注意啦,这里的lock是用户级的lock,跟那个GIL没关系
加锁版本:
import threading,time num = 0 def run(n): lock.acquire() #计算前加锁 global num print(‘task‘,n) num +=1 lock.release() #计算后释放,避免sleep也等待 time.sleep(1) print("task done") lock = threading.Lock() start_time = time.time() task_list = [] for i in range(1000): t1=threading.Thread(target=run,args=(i,)) t1.start() task_list.append(t1) for j in task_list : j.join() print(num)
RLock(递归锁)
说白了就是在一个大锁中还要再包含子锁
import threading,time def run1(): print("grab the first part data") lock.acquire() global num num +=1 lock.release() return num def run2(): print("grab the second part data") lock.acquire() global num2 num2+=1 lock.release() return num2 def run3(): lock.acquire() res = run1() print(‘--------between run1 and run2-----‘) res2 = run2() lock.release() print(res,res2) if __name__ == ‘__main__‘: num,num2 = 0,0 lock = threading.RLock() for i in range(10): t = threading.Thread(target=run3) t.start() while threading.active_count() != 1: #加上主线程一共11个 print(threading.active_count()) else: print(‘----all threads done---‘) print(num,num2)
Semaphore(信号量)
互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
import threading,time def run(n): semaphore.acquire() print(‘task‘,n) time.sleep(1) semaphore.release() print("task done") semaphore = threading.BoundedSemaphore(5) start_time = time.time() task_list = [] for i in range(23): t1=threading.Thread(target=run,args=(i,)) t1.start() task_list.append(t1) for j in task_list : j.join()
#设置同时并行执行的数量,避免系统崩溃
#同时只能有5个线程并行执行,空出来一个线程在进去一个
执行结果:
task 0
task 1
task 2
task 3
task 4
task done
task done
task 6
task done
task done
task 8
task 7
task 5
task done
task 9
task done
task done
task 10
task done
task done
task 11
Events
通过Event来实现两个或多个线程间的交互
can wait for the flag to be set, or set or clear the flag themselves.
event = threading.Event()
# a client thread can wait for the flag to be set
event.wait() #暂停
# a server thread can set or reset it
event.set()
event.clear()
def lighter(): num = 0 while True: if num >20 and num <30: event.set() elif num > 30: event.clear() num = 0 else: pass num += 1 def car(): if event.is_set(): print(‘telsla is allowed going.‘) else: print(‘telsla is not going.‘) event = threading.Event() light = threading.Thread(target=lighter,) light.start() for i in range(100): my_car = threading.Thread(target=car) my_car.start()