Python学习——多线程学习threading模块

进程的概念:

An executing instance of a program is called a process.

Each process provides the resources needed to execute a program. A process has a virtual address space, executable code, open handles to system objects, a security context, a unique process identifier, environment variables, a priority class, minimum and maximum working set sizes, and at least one thread of execution. Each process is started with a single thread, often called the primary thread, but can create additional threads from any of its threads.

线程的概念:

A thread is an execution context, which is all the information a CPU needs to execute a stream of instructions.

Suppose you're reading a book, and you want to take a break right now, but you want to be able to come back and resume reading from the exact point where you stopped. One way to achieve that is by jotting down the page number, line number, and word number. So your execution context for reading a book is these 3 numbers.

If you have a roommate, and she's using the same technique, she can take the book while you're not using it, and resume reading from where she stopped. Then you can take it back, and resume it from where you were.

Threads work in the same way. A CPU is giving you the illusion that it's doing multiple computations at the same time. It does that by spending a bit of time on each computation. It can do that because it has an execution context for each computation. Just like you can share a book with your friend, many tasks can share a CPU.

On a more technical level, an execution context (therefore a thread) consists of the values of the CPU's registers.

Last: threads are different from processes. A thread is a context of execution, while a process is a bunch of resources associated with a computation. A process can have one or many threads.

Clarification: the resources associated with a process include memory pages (all the threads in a process have the same view of the memory), file descriptors (e.g., open sockets), and security credentials (e.g., the ID of the user who started the process).

进程和线程的区别:

程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。

  1. Threads share the address space of the process that created it; processes have their own address space.
  2. Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
  3. Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
  4. New threads are easily created; new processes require duplication of the parent process.
  5. Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
  6. 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.

多线程的调用:

两种形式:

直接调用:

import threading

t1 = threading.Thread(target=函数名,args=(参数1,)) #生成一个线程实例。
t1.start() #启动线程,必须用start()来启动。注意不是run
类调用:
class MyThread(threading.Thread):
    def __init__(self,num):
        super(MyThread,self).__init__()
        self.num = num
 
    def run(self):#这个动态属性名必须是run
 
        print("running on number:%s" %self.num)
 
        time.sleep(3)
 
if __name__ == '__main__':
 
    t1 = MyThread(1)   #直接建立实例即可。
    t2 = MyThread(2)
    t1.start()  #这个继承的类里面没有start的,但是还是可以使用,并且就是运行run。所以,注意了,继承的类里面必须是run哦。
    t2.start()

多线程的常见使用功能:

线程名.join()  这个就是等待,线程执行完成才能继续运行下面的代码

join的实现例子:

 1 import threading
 2 import time
 3 
 4 class MyThread(threading.Thread):
 5     def __init__(self,num, join_time):  #num代表线程数,join_time就是代表等待时间
 6         super(MyThread,self).__init__()
 7         self.num = num
 8         self.join_time = join_time
 9 
10     def run(self):  #这个名称是固定的,必须是run才可以
11         print("run thread number is %s" %self.num)
12         time.sleep(self.join_time)
13         #print(threading.current_thread())
14         print("thread running is ending.")
15 
16 
17 if __name__ == '__main__':
18     '''同时启动多个线程,统计程序全部运行时间'''
19     start_time = time.time()
20     t_obj = [] #用来存储线程名
21     for i in range(20, 0, -2): #采用for循环直接启动线程
22         t = MyThread("t%s" % i, i)
23         t_obj.append(t)
24         #t2= MyThread("t2",6)
25         t.start()  #线程的启动要用start,它是子线程与父进程是并行的,所以不会阻塞循环,会继续启动
26 
27     print("The present threading count is %s" % threading.active_count())
28     #print(threading.current_thread()) #显示当前的线程
29     for i in t_obj:
30         print("The present process name is %s" % i)
31         i.join()  #等待每一个线程的完成。因为线程是并行的,所以线程的用时顺序不会影响结果
32     print("Total cost time:%s" % (time.time() - start_time))
33     #t2.start()
34     #t1.join()  # 等待t1线程执行结束,才会继续执行下面的语句。
35     #t2.join()

线程的类:设定相对特殊,里面的function命名必须是run才能够正确执行:

 1 import threading
 2 import time
 3 
 4 
 5 def testing(a):
 6     print(a)
 7     time.sleep(2)
 8     print("end the process %s" % a)
 9 
10 
11 class MyThread(threading.Thread):
12     def __init__(self,func, cont):
13         super(MyThread,self).__init__()
14         self.func = func
15         self.cont = cont
16 
17     def run(self):
18         '''this function is used to testing the insert of function.'''
19         self.func(self.cont)
20         print("The current thread count is %s" % threading.active_count() )
21         # print("run thread number is %s" %self.num)
22         # time.sleep(2)
23         # print("thread running is ending.")
24 
25 
26 if __name__ == '__main__':
27     t1 = MyThread(testing, "t1")
28     t2 = MyThread(testing, "t2")
29 
30     t1.start()  #线程的启动要用start
31     t2.start()    

Deamon,守护线程,也就是仆从线程,在主线程结束之后自动结束的线程:

 1 import threading
 2 import time
 3 
 4 class MyThread(threading.Thread):
 5     def __init__(self,num, join_time):  #num代表线程数,join_time就是代表等待时间
 6         super(MyThread,self).__init__()
 7         self.num = num
 8         self.join_time = join_time
 9 
10     def run(self):  #这个名称是固定的,必须是run才可以
11         print("run thread number is %s" %self.num)
12         time.sleep(self.join_time)
13         #print(threading.current_thread())
14         print("thread running is ending.")
15 
16 
17 if __name__ == '__main__':
18     '''同时启动多个线程,统计程序全部运行时间'''
19     start_time = time.time()
20     t_obj = [] #用来存储线程名
21     for i in range(20, 0, -2): #采用for循环直接启动线程
22         t = MyThread("t%s" % i, i)
23         t_obj.append(t)
24         t.setDaemon(True)   #设置之后,将线程变为守护线程。程序会等待主线程执行完毕,不会等待守护(子)线程
25         #需要设置在start 之前。
26         #t2= MyThread("t2",6)
27         t.start()  #线程的启动要用start,它不会阻塞循环,会继续启动
28 
29     a = MyThread("this is not daemon.", 1)
30     a.start()
31 
32     print("cost time:%s" % (time.time() - start_time))

公共变量数据加锁,实现多线程操作数据的结果叠加(python3以后不会有这个问题):

Lock()

threading.Lock().acquire()    #启动锁,要在改动数据前

threading.Lock().release()   #释放锁

RLock(递归锁):

其他一样,但是这个可以启动多个锁。

设定最多同时启动的线程数量()

信号量:threading.BoundedSemaphore(信号的数量,int)  #启动的线程的数量 

使用方法和锁类似,把东西放在运行的函数里面即可。

 1 import threading
 2 import time
 3 
 4 
 5 class MyThread(threading.Thread):
 6     def __init__(self, num, join_time):  # num代表线程数,join_time就是代表等待时间
 7         super(MyThread, self).__init__()
 8         self.num = num
 9         self.join_time = join_time
10 
11     def run(self):  # 这个名称是固定的,必须是run才可以
12         semaphore.acquire()  #类似线程锁
13         print("run thread number is %s" % self.num)
14         time.sleep(self.join_time)
15         semaphore.release()   #释放线程锁
16         # print(threading.current_thread())
17         print("thread running is ending.")
18 
19 
20 if __name__ == '__main__':
21     '''同时启动多个线程,统计程序全部运行时间'''
22     start_time = time.time()
23     semaphore = threading.BoundedSemaphore(5) #信号量的参数。5,表示最多同时的线程数量。结束一个,就可以立即下一个线程。
24     t_obj = []  # 用来存储线程名
25     for i in range(20, 0, -2):  # 采用for循环直接启动线程
26         t = MyThread("t%s" % i, i)
27         t_obj.append(t)
28         # t2= MyThread("t2",6)
29         t.start()  # 线程的启动要用start,它不会阻塞循环,会继续启动
30 
31     # print(threading.current_thread()) #显示当前的线程
32     for i in t_obj:
33         print(i)
34         i.join()  # 等待每一个线程的完成。因为线程是并行的,所以线程的用时顺序不会影响结果
35     print("cost time:%s" % (time.time() - start_time))

参考网站:http://www.cnblogs.com/alex3714/articles/5230609.html

Event:相当于一个flag,类似全局变量

event.set() #就是表示设置了event.
event.isSet(): #检查event是否设立,已经设立,则为Ture.
event.wait()   #如果没有设置,则线程处于等待
event.clear()   #消除event,取消设置

 1 import time
 2 import threading
 3 
 4 
 5 event = threading.Event()  ##可以理解为一个flag
 6 
 7 def lighter():
 8     count = 0
 9     event.set() #先设置绿灯
10     while True:
11         if count >5 and count < 10: #改成红灯
12             event.clear() #把标志位清了
13             print("33[41;1mred light is on....33[0m")
14         elif count >10:
15             event.set() #变绿灯
16             count = 0
17         else:
18             print("33[42;1mgreen light is on....33[0m")
19         time.sleep(1)
20         count +=1
21 
22 def car(name):
23     while True:
24         if event.is_set(): #代表绿灯
25             print("[%s] running..."% name )
26             time.sleep(1)
27         else:
28             print("[%s] sees red light , waiting...." % name)
29             event.wait()  ##会一直等待到event to be set.
30             print("33[34;1m[%s] green light is on, start going...33[0m" %name)
31 
32 
33 light = threading.Thread(target=lighter,)
34 light.start()
35 
36 car1 = threading.Thread(target=car,args=("macan",))
37 car1.start()



队列queue:

作用:程序之间解耦;提高运行效率

class queue.Queue(maxsize=0) #先入先出
class queue.LifoQueue(maxsize=0) #last in fisrt out 
class queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列
Queue.qsize()
Queue.empty() #return True if empty  
Queue.full() # return True if full 
Queue.put(itemblock=Truetimeout=None)
Queue.put_nowait(item #不等待,直接回复错误结果,避免卡死
Queue.get(block=Truetimeout=None#等待的时间只有timeout 秒
Queue.get_nowait()
 1 import queue
 2 
 3 q = queue.Queue() #先入先出
 4 
 5 q.put("d1")
 6 q.put("d2")
 7 q.put("d3")
 8 print(q.qsize())
 9 print(q.get()) #取数据,按顺序取
10 print(q.get())
11 print(q.get())
12 
13 #q.get_nowait()  #不等待,直接回复错误结果,避免卡死
14 #q.get(timeout=1)  #等待的时间只有1s
15 #q.get()  #不能再取了,因为里面没有了,会卡死。
16 
17 q = queue.LifoQueue(3) #后入先出
18 
19 q.put("d1")
20 q.put("d2")
21 q.put("d3")
22 print(q.qsize())
23 print(q.full())  #判断是否队列存储满,返回布尔值
24 print(q.empty())  #判断是否队列是否为空,返回布尔值
25 print(q.get()) #取数据,按反序取
26 print(q.get())
27 print(q.get())
28 
29 
30 q = queue.PriorityQueue(3) #优先级输出
31 
32 q.put((10,"d1"))
33 q.put((11,"d2"))
34 q.put((1,"d3"))
35 print(q.qsize())
36 print(q.full())  #判断是否队列存储满,返回布尔值
37 print(q.empty())  #判断是否队列是否为空,返回布尔值
38 print(q.get()) #取数据,按照优先级取,从小到大
39 print(q.get())
40 print(q.get())
原文地址:https://www.cnblogs.com/Ian-learning/p/8624219.html