多线程编程

1. 进程和线程:

   进程是一个执行中的程序,每个进程都有自己的地址空间,内存,数据栈以及其他用于追踪执行的辅助数据。

   线程是在同一个进程下执行的,并共享相同的上下文。线程包括开始,执行顺序和结束三部分。一个线程中各个线程和主线程共用同一片数据空间,相比较独立的进程而言,线程间的信息共享和通信更加容易。线程一般是并发执行的。

   进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

   1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

   2) 线程的划分尺度小于进程,使得多线程程序的并发性高。

   3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

   4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

   5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

2. 全局解释器锁:

   python在设计的时候,在主循环中同时只能有一个控制线程在执行(尽管python 解释器可以运行多个线程,但在任意给定时刻,只能有一个程序运行)。

   对python虚拟机的访问是全局解释器锁(GIL)控制的。这个锁就是用来保证同时只能有一个线程运行的。

          1.设置 GIL。

          2.切换进一个线程去运行。

          3.执行下面操作之一。

             a.指定数量的字节码指令。

             b.线程主动让出控制权(可以调用 time.sleep(0)来完成)。

          4.把线程设置回睡眠状态(切换出线程)。
          5.解锁 GIL。
          6.重复上述步骤

3. python使用线程:

 1 import time
 2 import threading
 3 def loop1():
 4     print('Start loop 1 at : ', time.ctime())
 5     time.sleep(4)
 6     print('End loop 1 at : ', time.ctime())
 7 
 8 def loop2():
 9     print('Start loop 2 at : ', time.ctime())
10     time.sleep(2)
11     print('End loop 2 at : ', time.ctime())
12 
13 def main():
14     print("Startig at : ", time.ctime())
15     #loop1()
16     #loop2()
17     threading.Thread(loop1(),())
18     threading.Thread(loop2(), ())
19     time.sleep(6)
20     print("All done at : ", time.ctime())
21 
22 if __name__ == '__main__':
23     main()

4. threading模块中的Thread类:

   threading 模块支持守护线程,其工作方式是:守护线程一般是一个等待客户端请求服务的服务器。如果没有客户端请求,守护线程就是空闲的。如果把一个线程设置为守护线程,就表示这个线程是不重要的,进程退出时不需要等待这个线程执行完成。 

   a. 创建Thread实例,传给它一个函数

 1 from time import ctime,sleep
 2 import threading
 3 
 4 loops = [4, 2]
 5 
 6 def loop(nloop, nsec):
 7     print('Start loop {0} at : {1}'.format(nloop+1, ctime()))
 8     sleep(nsec)
 9     print('End loop {0} at : {1}'.format(nloop+1, ctime()))
10 
11 def main():
12     print("Startig at : ", ctime())
13     threads = []
14     nloops = range(len(loops))
15 
16     for i in nloops:
17         t = threading.Thread(target=loop, args=(i, loops[i]))
18         threads.append(t)
19 
20     for i in nloops:
21         threads[i].start()
22 
23     for i in nloops:
24         threads[i].join()
25 
26     print("All DONE at : ", ctime())
27 
28 if __name__ == '__main__':
29     main()

   b. 创建Thread实例,传给它一个可以调用的类实例

 1 import threading
 2 from time import ctime,sleep
 3 
 4 loops = [4, 2]
 5 class ThreadFunc(object):
 6     def __init__(self, func, args, name=''):
 7         self.name = name
 8         self.func = func
 9         self.args = args
10 
11     def __call__(self):
12         self.func(*self.args)
13 
14 def loop(nloop, nsec):
15     print('Start loop {0} at : {1}'.format(nloop + 1, ctime()))
16     sleep(nsec)
17     print('End loop {0} at : {1}'.format(nloop + 1, ctime()))
18 
19 def main():
20     print("Startig at : ", ctime())
21     threads = []
22     nloops = range(len(loops))
23 
24     for i in nloops:
25         t = threading.Thread(target=ThreadFunc(loop, (i, loops[i]), loop.__name__))
26         threads.append(t)
27 
28     for i in nloops:
29         threads[i].start()
30 
31     for i in nloops:
32         threads[i].join()
33 
34     print("All DONE at : ", ctime())
35 
36 if __name__ == '__main__':
37     main()

5. 锁:

   锁有两种状态:锁定和未锁定 

   只支持两个函数: 获得锁和释放锁

   当多线程开始挣锁时,允许第一个获得锁的线程进入临界区,并执行代码。所有之后到达的线程将阻塞,直到第一个线程执行结束,退出临界区,并释放锁。其他等待的线程获得锁并进入临界区,那些被阻塞的线程是没有顺序的,胜出线程的选择是不确定的。

 1 from atexit import register
 2 from random import randrange
 3 from threading import Thread, currentThread, Lock
 4 from time import sleep, ctime
 5 
 6 class CleaOutputset(set):
 7     def __str__(self):
 8         return (', '.join(x for x in self))
 9 
10 lock = Lock()
11 loops = (randrange(2, 5) for x in range(randrange(3, 7)))
12 remaining = CleaOutputset()
13 
14 def loop(nsec):
15     myname = currentThread().name
16     lock.acquire()
17     remaining.add(myname)
18     print('[%s] Started %s' % (ctime(), myname))
19     lock.release()
20     sleep(nsec)
21     lock.acquire()
22     remaining.remove(myname)
23     print('[%s] Completed %s (%d secs)' % (ctime(), myname, nsec))
24     print('     (remaining: %s)' % (remaining or 'NONE'))
25     lock.release()
26 
27 def main():
28     for pause in loops:
29         Thread(target=loop(), args=(pause,)).start()
30 
31 @register
32 def atexit():
33     print("All DONE at: ", ctime())
34 
35 if __name__ == '__main__':
36     main()
原文地址:https://www.cnblogs.com/chengchengaqin/p/9722268.html