顺便聊一下多线程 VS 多进程(一)

多线程 vs 多进程

  • 程序:一堆代码以文本形式存入一个文档
  • 进程:程序运行的一个状态
    • 包含地址空间、内容、数据栈等
    • 每个进程由自己完全独立的运行环境,多进程共享数据是一个问题
  • 线程
    • 一个进程的独立运行片段,一个进程可以有多个线程
    • 轻量化的进程
    • 一个进程的多个线程间共享数据和上下文运行环境
    • 共享互斥问题
  • 全局解释器锁(GTL)
    • python 代码的执行是由python 虚拟机进行控制
    • 在主循环中只能有一个控制线程在执行
  • python 包
    • thread:有问题,不好用,python3改成了_thread
    • threading:通行的包
    • 案例01: 顺序执行,耗时比较长 ”’
      利用time函数,生成两个函数
      程序调试
      计算总的运行时间
      ”’
	import time

	def loop1():

	    # ctime 得到当前时间

	    print("Start loop 1 at : ",time.ctime())

	    time.sleep(4)

	    print("End loop 1 at : ", time.ctime())

	def loop2():

	    # ctime 得到当前时间

	    print("Start loop 2 at : ", time.ctime())

	    # 睡眠多长时间,单位是秒

	    time.sleep(2)

	    print("End loop 2 at : ", time.ctime())

	def main():

	    print("Starting at : ", time.ctime())

	    loop1()

	    loop2()

	    print("All done at : ", time.ctime())

	if __name__ == '__main__':

	    main()

Starting at : Tue Aug 13 19:10:31 2019

		Start loop 1 at :  Tue Aug 13 19:10:31 2019

		End loop 1 at :  Tue Aug 13 19:10:35 2019

		Start loop 2 at :  Tue Aug 13 19:10:35 2019

		End loop 2 at :  Tue Aug 13 19:10:37 2019

		All done at :  Tue Aug 13 19:10:37 2019

- 案例02:改用多线程,缩短总时间,使用_thread
	```python
    '''
	利用time函数,生成两个函数
	程序调试
	计算总的运行时间
	'''
	

	import time

	import _thread as thread

	def loop1():

	    # ctime 得到当前时间

	    print("Start loop 1 at : ",time.ctime())

	    time.sleep(4)

	    print("End loop 1 at : ", time.ctime())

	def loop2():

	    # ctime 得到当前时间

	    print("Start loop 2 at : ", time.ctime())

	    # 睡眠多长时间,单位是秒

	    time.sleep(2)

	    print("End loop 2 at : ", time.ctime())

	def main():

	    print("Starting at : ", time.ctime())

	    # 启动多线程的意思是用多线程去执行某个函数

	    # 启动多线程函数为start_new_thread

	    # 参数两个,一个是需要运行的函数名,第二个是函数的参数作为元组使用,为空则使用空元组

	    # 注意,如果函数只有一个参数,需要参数后有一个逗号

	    thread.start_new_thread(loop1, ())

	    thread.start_new_thread(loop2, ())

	    print("All done at : ", time.ctime())

	if __name__ == '__main__':

	    main()

	    while True:

	        time.sleep(1)

   		Starting at :  Tue Aug 13 19:14:47 2019

		All done at :  Tue Aug 13 19:14:47 2019

		Start loop 1 at :  Tue Aug 13 19:14:47 2019

		Start loop 2 at :  Tue Aug 13 19:14:47 2019

		End loop 2 at :  Tue Aug 13 19:14:49 2019

		End loop 1 at :  Tue Aug 13 19:14:51 2019

- 案例03:多线程,传参数
    ```python
    # 利用time延时函数,生成两个函数
	# 利用多线程调用
	# 计算总运行时间
	# 练习带参数的多线程启动方法
	import time
	# 导入多线程包并更名为thread
	import _thread as thread
	

	def loop1(in1):

	    # ctime 得到当前时间

	    print('Start loop 1 at: ', time.ctime())

	    # 把参数打印出来

	    print("我是参数", in1)

	    # 睡眠多长时间,单位是秒

	    time.sleep(4)

	    print('End loop 1 at: ', time.ctime())

	def loop2(in1, in2):

	    # ctime 得到当前时间

	    print('Start loop 2 at: ', time.ctime())

	    # 把参数in1 和 in2 打印出来,代表使用

	    print("我是参数", in1, "和参数", in2)

	    # 睡眠多长时间,单位是秒

	    time.sleep(4)

	    print('End loop 2 at: ', time.ctime())

	def main():

	    print("Starting at : ", time.ctime())

	    # 启动多线程的意思是用多线程去执行某个函数

	    # 启动多线程函数为start_new_thread

	    # 参数两个,一个是需要运行的函数名,第二个是函数的参数作为元组使用,为空则使用空元组

	    # 注意,如果函数只有一个参数,需要参数后有一个逗号

	    thread.start_new_thread(loop1, ("王老大", ))

	    thread.start_new_thread(loop2, ("王大鹏", "王晓鹏"))

	    print("All done at : ", time.ctime())

	if __name__ == '__main__':

	    main()

	    # 一定要有while语句

	    # 因为启动多线程后本程序就作为主线程存在

	    # 如果主线程执行完毕,则子线程可能也需要终止

	    while True:

	       time.sleep(10)

    ```

	    Starting at :  Tue Aug 13 19:17:10 2019

		All done at :  Tue Aug 13 19:17:10 2019

		Start loop 1 at:  Tue Aug 13 19:17:10 2019

		我是参数 王老大

		Start loop 2 at:  Tue Aug 13 19:17:10 2019

		我是参数 王大鹏 和参数 王晓鹏

		End loop 1 at:  Tue Aug 13 19:17:14 2019

		End loop 2 at:  Tue Aug 13 19:17:14 2019

  • threading的使用
    • 直接利用threading.Thread生成Thread实例
      1. t = threading.Thread(target=xxx, args=(xxx, ))
      2. t.start(): 启动多线程
      3. t.join(): 等待多线程执行完成
      4. 案例04 “`python
        # 利用time延时函数,生成两个函数
        # 利用多线程调用
        # 计算总运行时间
        # 练习带参数的多线程启动方法
        import time
        # 导入多线程包并更名为thread
        import threading
		def loop1(in1):

		    # ctime 得到当前时间

		    print('Start loop 1 at: ', time.ctime())

		    # 把参数打印出来

		    print("我是参数", in1)

		    # 睡眠多长时间,单位是秒

		    time.sleep(4)

		    print('End loop 1 at: ', time.ctime())

		def loop2(in1, in2):

		    # ctime 得到当前时间

		    print('Start loop 2 at: ', time.ctime())

		    # 把参数in1 和 in2 打印出来,代表使用

		    print("我是参数", in1, "和参数 ", in2)

		    # 睡眠多长时间,单位是秒

		    time.sleep(2)

		    print('End loop 2 at: ', time.ctime())

		def main():

		    print("Starting at: ", time.ctime())

		    # 生成threading.Thread实例

		    t1 = threading.Thread(target=loop1, args=("王老大",))

		    t1.start()

		    t2 = threading.Thread(target=loop2, args=("王大鹏", "王小鹏"))

		    t2.start()

		    print("All done at: ", time.ctime())

		if __name__ == '__main__':

		    main()

		    # 一定要有while语句

		    # 因为启动多线程后本程序就作为主线程存在

		    # 如果主线程执行完毕,则子线程可能也需要终止

		    while True:

		        time.sleep(10)

        ```

		    Starting at:  Tue Aug 13 19:19:42 2019

			Start loop 1 at:  Tue Aug 13 19:19:42 2019

			我是参数 王老大

			Start loop 2 at: All done at:  Tue Aug 13 19:19:42 2019

			Tue Aug 13 19:19:42 2019

			我是参数 王大鹏 和参数  王小鹏

			End loop 2 at:  Tue Aug 13 19:19:44 2019

			End loop 1 at:  Tue Aug 13 19:19:46 2019

    5. 案例05:加入join后比较案例04的结果的异同
        ```python
        # 利用time延时函数,生成两个函数
		# 利用多线程调用
		# 计算总运行时间
		# 练习带参数的多线程启动方法
		import time
		# 导入多线程包并更名为thread
		import threading
		

		def loop1(in1):

		    # ctime 得到当前时间

		    print('Start loop 1 at: ', time.ctime())

		    # 把参数打印出来

		    print("我是参数", in1)

		    # 睡眠多长时间,单位是秒

		    time.sleep(4)

		    print('End loop 1 at: ', time.ctime())

		def loop2(in1, in2):

		    # ctime 得到当前时间

		    print('Start loop 2 at: ', time.ctime())

		    # 把参数in1 和 in2 打印出来,代表使用

		    print("我是参数", in1, "和参数 ", in2)

		    # 睡眠多长时间,单位是秒

		    time.sleep(2)

		    print('End loop 2 at: ', time.ctime())

		def main():

		    print("Starting at: ", time.ctime())

		    # 生成threading.Thread实例

		    t1 = threading.Thread(target=loop1, args=("王老大",))

		    t1.start()

		    t2 = threading.Thread(target=loop2, args=("王大鹏", "王小鹏"))

		    t2.start()

		    t1.join()

		    t2.join()

		    print("All done at: ", time.ctime())

		if __name__ == '__main__':

		    main()

		    # 一定要有while语句

		    # 因为启动多线程后本程序就作为主线程存在

		    # 如果主线程执行完毕,则子线程可能也需要终止

		    while True:

		        time.sleep(10)

        ```

        	Starting at:  Tue Aug 13 19:21:58 2019

			Start loop 1 at:  Tue Aug 13 19:21:58 2019

			我是参数 王老大

			Start loop 2 at:  Tue Aug 13 19:21:58 2019

			我是参数 王大鹏 和参数  王小鹏

			End loop 2 at:  Tue Aug 13 19:22:00 2019

			End loop 1 at:  Tue Aug 13 19:22:02 2019

			All done at:  Tue Aug 13 19:22:02 2019

    - 守护线程-daemon
        - 如果在程序中将子线程设置成守护线程,则子线程会在主线程结束的时候自动退出
        - 一般认为,守护线程不重要或者不允许离开主线程独立运行
        - 守护线程案例能否有效果跟环境相关
        - 案例06非守护线程
            ```python
            import time
			import threading
			

			def fun():

			    print("Start fun")

			    time.sleep(2)

			    print("end fun")

			print("Main thread")

			t1 = threading.Thread(target=fun, args=() )

			t1.start()

			time.sleep(1)

			print("Main thread end")

            ```

	            Main thread

				Start fun

				Main thread end

				end fun

        - 案例07守护线程
            ```python
            import time
			import threading
			

			def fun():

			    print("Start fun")

			    time.sleep(2)

			    print("end fun")

			print("Main thread")

			t1 = threading.Thread(target=fun, args=() )

			# 启动之前设置

			t1.setDaemon(True)

			# t1.daemon = True

			t1.start()

			time.sleep(1)

			print("Main thread end")

            ```

	            Main thread

				Start fun

				Main thread end

    - 线程常用属性
        - threading.currentThread:返回当前线程变量
        - threading.enumerate:返回一个包含正在运行的线程的list,正在运行的线程指的是线程启动后,结束前的状态
        - threading.activeCount: 返回正在运行的线程数量,效果跟 len(threading.enumerate)相同
        - thr.setName: 给线程设置名字
        - thr.getName: 得到线程的名字
        - 案例08
            ```python
            import time
			import threading
			

			def loop1():

			    # ctime 得到当前时间

			    print("Start loop 1 at : ",time.ctime())

			    time.sleep(6)

			    print("End loop 1 at : ", time.ctime())

			def loop2():

			    # ctime 得到当前时间

			    print("Start loop 2 at : ",time.ctime())

			    time.sleep(1)

			    print("End loop 2 at : ", time.ctime())

			def loop3():

			    # ctime 得到当前时间

			    print("Start loop 3 at : ",time.ctime())

			    time.sleep(5)

			    print("End loop 3 at : ", time.ctime())

			def main():

			    print("Starting at: ", time.ctime())

			    # 生成threading.Thread实例

			    t1 = threading.Thread(target=loop1, args=( ))

			    # setName是给每一个子线程设置一个名字

			    t1.setName("THR_1")

			    t1.start()

			    t2 = threading.Thread(target=loop2, args=( ))

			    t2.setName("THR_2")

			    t2.start()

			    t3 = threading.Thread(target=loop3, args=( ))

			    t3.setName("THR_3")

			    t3.start()

			    # 预期3秒后,thread2已经结束

			    time.sleep(3)

			    # enumerate 得到正在运行子线程,即子线程1和子线程3

			    for thr in threading.enumerate():

			        # getName能够得到线程的名字

			        print("正在运行的线程名字是:  {0}".format(thr.getName()))

			    print("正在运行的子线程数量为:  {0}".format(threading.activeCount()))

			    print("All done at: ", time.ctime())

			if __name__ == '__main__':

			    main()

			    # 一定要有while语句

			    # 因为启动多线程后本程序就作为主线程存在

			    # 如果主线程执行完毕,则子线程可能也需要终止

			    while True:

			        time.sleep(10)

            ```

	            Starting at:  Tue Aug 13 19:28:20 2019

				Start loop 1 at :  Tue Aug 13 19:28:20 2019

				Start loop 2 at :  Tue Aug 13 19:28:20 2019

				Start loop 3 at :  Tue Aug 13 19:28:20 2019

				End loop 2 at :  Tue Aug 13 19:28:21 2019

				正在运行的线程名字是:  MainThread

				正在运行的线程名字是:  THR_1

				正在运行的线程名字是:  THR_3

				正在运行的子线程数量为:  3

				All done at:  Tue Aug 13 19:28:23 2019

				End loop 3 at :  Tue Aug 13 19:28:25 2019

				End loop 1 at :  Tue Aug 13 19:28:26 2019

    - 直接继承自threading.Thread
        - 直接继承Thread
        - 重写run函数
        - 类实例可以直接运行
        - 案例09
            ```python
            import threading
			import time
			

			# 1. 类需要继承来自threading.Thread

			class MyThread(threading.Thread):

			    def __init__(self, arg):

			        super().__init__()

			        self.arg = arg

			    # 2. 必须重写run函数,run函数代表的是真正执行的功能

			    def run(self):

			        time.sleep(2)

			        print("The args for this class is {0}".format(self.arg))

			for i in range(5):

			    t = MyThread(i)

			    t.start()

			    t.join()

			print("Main thread is done!!!!!!!!")

            ```

	            The args for this class is 0

				The args for this class is 1

				The args for this class is 2

				The args for this class is 3

				The args for this class is 4

				Main thread is done!!!!!!!!

        - 案例10  工业风案例
            ```python
            import threading
			from time import sleep, ctime
			

			loop = [4, 2]

			class ThreadFunc:

			    def __init__(self, name):

			        self.name = name

			    def loop(self, nloop, nsec):

			        '''

			        :param nloop:loop函数的名称

			        :param nsec:系统休眠时间

			        :return:

			        '''

			        print('Start loop', nloop, 'at ', ctime())

			        sleep(nsec)

			        print('Done loop', nloop, 'at ', ctime())

			def main():

			    print("Starting at: ", ctime())

			    # ThreadFunc("loop").loop 跟以下两个式子相等

			    # t = ThreadFunc("loop")

			    # t.loop

			    # 以下t1 和 t2的定义方式相等

			    t = ThreadFunc("loop")

			    t1 = threading.Thread( target=t.loop, args=("LOOP1", 4))

			    # 下面这种写法更西方人,工业化一点

			    t2 = threading.Thread( target=ThreadFunc('loop').loop, args=('LOOP2', 2))

			    # 常见错误写法

			    # t1 = threading.Thread(target=ThreadFunc('loop').loop(100,4))

			    # t2 = threading.Thread(target=ThreadFunc('loop').loop(100,2))

			    t1.start()

			    t2.start()

			    t1.join()

			    t2.join()

			    print("All done at: ", ctime())

			if __name__ == '__main__':

			    main()

			    # 一定要有while语句

			    # 因为启动多线程后本程序就作为主线程存在

			    # 如果主线程执行完毕,则子线程可能也需要终止

			    while True:

			        sleep(10)

            ```

	            Starting at:  Tue Aug 13 19:31:16 2019

				Start loop LOOP1 at  Tue Aug 13 19:31:16 2019

				Start loop LOOP2 at  Tue Aug 13 19:31:16 2019

				Done loop LOOP2 at  Tue Aug 13 19:31:18 2019

				Done loop LOOP1 at  Tue Aug 13 19:31:20 2019

				All done at:  Tue Aug 13 19:31:20 2019

正文完