九 利用socketserver实现并发
基于TCP服务端:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import socketserver 4 5 6 class MyServer(socketserver.BaseRequestHandler): 7 def handle(self): 8 print('conn is:', self.request) # <==>conn 9 print('addr is:', self.client_address) # <==> addr10 while True:11 try:12 # 收消息13 data = self.request.recv(1024)14 if not data:break15 print('收到客户端的消息是', data)16 # 发消息17 self.request.sendall(data.upper())18 except Exception as EX:19 print('错误提示:',EX)20 break21 22 23 if __name__ == '__main__':24 s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyServer) # 多线程;第一个参数,地址+端口;第二个参数,类 25 # s = socketserver.ForkingTCPServer(('127.0.0.1', 8080), MyServer) # 多进程;多进程的开销大于多线程 26 s.serve_forever()
基于TCP客户端:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from socket import * 4 ip_port = ('127.0.0.1', 8080) 5 back_log = 5 6 buffer_size = 1024 7 tcp_client = socket(AF_INET, SOCK_STREAM) 8 tcp_client.connect(ip_port) 9 while True:10 msg = input('>>').strip()11 if not msg:continue12 if msg == 'quit':break13 tcp_client.send(msg.encode('utf-8'))14 data = tcp_client.recv(buffer_size)15 print('收到服务端发来的消息:', data.decode('utf-8'))16 tcp_client.close()
基于UDP服务端
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import socketserver 4 5 6 class MyServer(socketserver.BaseRequestHandler): 7 def handle(self): 8 print(self.request) 9 print('收到客户端的消息是:', self.request[0].upper())10 self.request[1].sendto(self.request[0].upper(), self.client_address)11 12 13 if __name__ == '__main__':14 s = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyServer) # 第一个参数,地址+端口;第二个参数,类15 s.serve_forever()
基于UDP客户端
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from socket import * 4 ip_port = ('127.0.0.1', 8080) 5 buffer_size = 1024 6 udp_client = socket(AF_INET, SOCK_DGRAM) # SOCK_DGRAM:数据报式套接字 7 while True: 8 msg = input('>>').strip() 9 udp_client.sendto(msg.encode('utf-8'), ip_port)10 data, addr = udp_client.recvfrom(buffer_size)11 print(data.decode('utf-8'))12 print(addr)
十 认证客户端的合法性
如果想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么可以利用hmac+加盐的方法来实现。
1 # _*_coding:utf-8_*_ 2 __author__ = 'Linhaifeng' 3 from socket import * 4 import hmac, os 5 6 secret_key = b'alex bang bang bang' 7 8 9 def conn_auth(conn):10 '''11 认证客户端链接12 :param conn:13 :return:14 '''15 print('开始验证新链接的合法性')16 msg = os.urandom(32) # 随机生成的;b'\xa3\x9d\xaa\x94\x9e\x89\xe9\xc9\xc3r\xf9E\xe0w\x82=\xaac-\x04\xd8:\xea\x07\xad\x1dx\x1er\xe0\x7f\x02'17 conn.sendall(msg)18 h = hmac.new(secret_key, msg) # <hmac.HMAC object at 0x000000D5DA4824E0>19 digest = h.digest() # 随机生成的;b'\x17!*\xae6\x81\xfe|)\x138\xfa2o%\x1a'20 respone = conn.recv(len(digest))21 return hmac.compare_digest(respone, digest) # 比较第一个参数和第二个参数;相同,返回True,反之也成立22 23 24 def data_handler(conn, bufsize=1024):25 if not conn_auth(conn):26 print('该链接不合法,关闭')27 conn.close()28 return29 print('链接合法,开始通信')30 while True:31 data = conn.recv(bufsize)32 if not data: break33 conn.sendall(data.upper())34 35 36 def server_handler(ip_port, bufsize, backlog=5):37 '''38 只处理链接39 :param ip_port:40 :return:41 '''42 tcp_socket_server = socket(AF_INET, SOCK_STREAM)43 tcp_socket_server.bind(ip_port)44 tcp_socket_server.listen(backlog)45 while True:46 conn, addr = tcp_socket_server.accept()47 print('新连接[%s:%s]' % (addr[0], addr[1]))48 data_handler(conn, bufsize)49 50 51 if __name__ == '__main__':52 ip_port = ('127.0.0.1', 9999)53 bufsize = 102454 server_handler(ip_port, bufsize)
服务端
1 # _*_coding:utf-8_*_ 2 __author__ = 'Linhaifeng' 3 from socket import * 4 import hmac, os 5 6 secret_key = b'alex bang bang bang' 7 8 9 def conn_auth(conn):10 '''11 认证客户端链接12 :param conn:13 :return:14 '''15 print('开始验证新链接的合法性')16 msg = os.urandom(32)17 conn.sendall(msg)18 h = hmac.new(secret_key, msg)19 digest = h.digest()20 respone = conn.recv(len(digest))21 return hmac.compare_digest(respone, digest)22 23 24 def data_handler(conn, bufsize=1024):25 if not conn_auth(conn):26 print('该链接不合法,关闭')27 conn.close()28 return29 print('链接合法,开始通信')30 while True:31 data = conn.recv(bufsize)32 if not data: break33 conn.sendall(data.upper())34 35 36 def server_handler(ip_port, bufsize, backlog=5):37 '''38 只处理链接39 :param ip_port:40 :return:41 '''42 tcp_socket_server = socket(AF_INET, SOCK_STREAM)43 tcp_socket_server.bind(ip_port)44 tcp_socket_server.listen(backlog)45 while True:46 conn, addr = tcp_socket_server.accept()47 print('新连接[%s:%s]' % (addr[0], addr[1]))48 data_handler(conn, bufsize)49 50 51 if __name__ == '__main__':52 ip_port = ('127.0.0.1', 9999)53 bufsize = 102454 server_handler(ip_port, bufsize)
客户端(合法,其他均为非法)
十一 FTP服务器
实现如下功能:
1、用户加密认证
2、每个用户都有自己的家目录,且只能访问自己的家目录
3、允许用户在ftp server上随意切换目录(cd)
4、允许用户查看当前目录下的所有文件(ls)
5、允许上传和下载文件
6、文件传输过程中显示进度条
7、支持文件的断点续传
ftp server
目录结构:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import os,sys 4 PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 5 sys.path.append(PATH) 6 7 8 from core import main 9 10 11 if __name__ == '__main__':12 main.ArgvHandler()
ftp_server.py
1 [DEFAULT]2 3 [alex]4 Password =1235 Quotation = 1006 7 [root]8 Password = root9 Quotation = 100
accounts.cfg
1 #!/usr/bin/env python2 # -*- coding:utf-8 -*-3 import os4 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))5 6 ip = '127.0.0.1'7 port = 80808 9 ACCOUNT_PATH = os.path.join(BASE_DIR, 'conf', 'accounts.cfg')
settings.py
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import socketserver 4 import optparse 5 import socketserver 6 from conf import settings 7 from core import server 8 9 10 class ArgvHandler():11 def __init__(self):12 self.op = optparse.OptionParser()13 # self.op.add_option('-s', '--server', dest='server')14 # self.op.add_option('-P', '--port', dest='port')15 options, args = self.op.parse_args()16 # print(options) # {'server': '127.0.0.1', 'port': '8080'}17 # print(type(options)) # <class 'optparse.Values'>18 # print(options.server) # 127.0.0.119 # print(args)20 21 options, args = self.op.parse_args()22 self.verify_args(options, args)23 24 def verify_args(self, options, args):25 cmd = args[0]26 # 第一种方法27 # if cmd == 'start':28 # pass29 # else:30 # pass31 # 第二种方法32 if hasattr(self, cmd):33 func = getattr(self, cmd)34 func()35 36 def start(self):37 print('ths server is working...')38 s = socketserver.ThreadingTCPServer((settings.ip, settings.port), server.ServerHandler)39 s.serve_forever()40 41 def help(self):42 pass
main.py
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import socketserver 4 import json 5 import configparser 6 from conf import settings 7 import os 8 9 STATUS_CODE = { 10 250: "Invalid cmd format,e.g:{'action':'get','filename':'test.py','size':344}", 11 251: "Invalid cmd", 12 252: "Invalid auth data", 13 253: "Wrong username or password", 14 254: "Passed authentication", 15 255: "Filename doesn't provided", 16 256: "File doesn't exist on server", 17 257: "ready to send file", 18 258: "md5 verification", 19 800: "the file exist,but not enough,is continue?", 20 801: "the file exist!", 21 802: "ready to receive datas", 22 900: "md5 valdate success" 23 } 24 25 26 class ServerHandler(socketserver.BaseRequestHandler): 27 def handle(self): 28 while True: 29 data = self.request.recv(1024).strip() # self.request=conn 30 data = json.loads(data.decode('utf8')) 31 if data.get('action'): 32 if hasattr(self, data.get('action')): 33 func = getattr(self, data.get('action')) 34 func(**data) 35 else: 36 print('Invalid cmd') 37 else: 38 print('Invalid cmd') 39 40 def send_response(self, status_code): 41 response = {'status_code': status_code} 42 self.request.sendall(json.dumps(response).encode('utf8')) 43 44 def auth(self, **data): 45 username = data['username'] 46 password = data['password'] 47 username = self.authenticate(username, password) 48 if username: 49 self.send_response(254) 50 else: 51 self.send_response(253) 52 53 def authenticate(self, username, password): 54 cfg = configparser.ConfigParser() 55 cfg.read(settings.ACCOUNT_PATH) 56 if username in cfg.sections(): 57 if cfg[username]['Password'] == password: 58 self.username = username 59 self.mainPath = os.path.join(settings.BASE_DIR, 'home', self.username) 60 print('passed authenticate') 61 return username 62 63 def put(self, **data): 64 print('data', data) 65 file_name = data.get('file_name') 66 file_size = data.get('file_size') 67 target_path = data.get('target_path') 68 abs_path = os.path.join(self.mainPath, target_path, file_name) 69 has_received = 0 70 if os.path.exists(abs_path): 71 file_has_size = os.stat(abs_path).st_size 72 if file_has_size < file_size: 73 # 断点续传 74 self.request.sendall('800'.encode('utf8')) 75 choice = self.request.recv(1024).decode('utf8') 76 if choice == 'Y': 77 self.request.sendall(str(file_has_size).encode('utf8')) 78 has_received = file_has_size 79 f = open(abs_path, 'ab') 80 else: 81 f = open(abs_path, 'wb') 82 else: 83 # 文件完全存在 84 self.request.sendall('801'.encode('utf8')) 85 return 86 else: 87 self.request.sendall('802'.encode('utf8')) 88 f = open(abs_path, 'wb') 89 90 while has_received < file_size: 91 try: 92 data = self.request.recv(1024) 93 except Exception as EX: 94 break 95 f.write(data) 96 has_received += len(data) 97 f.close() 98 99 def ls(self, **data):100 file_list = os.listdir(self.mainPath)101 file_str = '\n'.join(file_list)102 if not len(file_list):103 file_str = '<empty dir>'104 self.request.sendall(file_str.encode('utf8'))105 106 def cd(self, **data):107 dirname = data.get('dirname')108 if dirname == '..':109 self.mainPath = os.path.dirname(self.mainPath)110 else:111 self.mainPath = os.path.join(self.mainPath, dirname)112 self.request.sendall(self.mainPath.encode('utf8'))113 114 def mkdir(self, **data):115 dirname = data.get('dirname')116 path = os.path.join(self.mainPath, dirname)117 if not os.path.exists(path):118 if '/' in path:119 os.makedirs(path)120 else:121 os.mkdir(path)122 self.request.sendall('create success'.encode('utf8'))123 else:124 self.request.sendall('dirname exist'.encode('utf8'))
server.py
ftp client
目录结构
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # import socket 4 # 5 # sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 6 # sk.connect(('127.0.0.1', 8080)) 7 import optparse 8 import socket 9 import json 10 import os, sys 11 STATUS_CODE = { 12 250: "Invalid cmd format,e.g:{'action':'get','filename':'test.py','size':344}", 13 251: "Invalid cmd", 14 252: "Invalid auth data", 15 253: "Wrong username or password", 16 254: "Passed authentication", 17 255: "Filename doesn't provided", 18 256: "File doesn't exist on server", 19 257: "ready to send file", 20 258: "md5 verification", 21 800: "the file exist,but not enough,is continue?", 22 801: "the file exist!", 23 802: "ready to receive datas", 24 900: "md5 valdate success" 25 } 26 27 28 class ClientHandler(object): 29 def __init__(self): 30 self.op = optparse.OptionParser() 31 self.op.add_option('-s', '--server', dest='server') 32 self.op.add_option('-P', '--port', dest='port') 33 self.op.add_option('-u', '--username', dest='username') 34 self.op.add_option('-p', '--password', dest='password') 35 36 self.options, self.args = self.op.parse_args() 37 38 self.verify_args(self.options, self.args) 39 self.make_connection() 40 self.mainPath = os.path.dirname(os.path.abspath(__file__)) 41 self.last = 0 42 43 def verify_args(self, options, args): 44 server = options.server 45 port = options.port 46 username = options.username 47 password = options.password 48 if int(port) > 0 and int(port) < 65535: 49 return True 50 else: 51 exit('the port is in 0-65535') 52 53 def make_connection(self): 54 self.sock = socket.socket() 55 self.sock.connect((self.options.server, int(self.options.port))) 56 57 def interactive(self): 58 print('begin to interactive...') 59 # self.authenticate() 60 if self.authenticate(): 61 while 1: 62 cmd_info = input('[%s]' % self.current_dir).strip() 63 cmd_list = cmd_info.split() 64 if hasattr(self, cmd_list[0]): 65 func = getattr(self, cmd_list[0]) 66 func(*cmd_list) 67 68 def put(self, *cmd_list): 69 # put 12.png images 70 actions, local_path, target_path = cmd_list 71 local_path = os.path.join(self.mainPath, local_path) 72 file_name = os.path.basename(local_path) 73 file_size = os.stat(local_path).st_size 74 data = { 75 'action': 'put', 76 'file_name': file_name, 77 'file_size': file_size, 78 'target_path': target_path 79 } 80 self.sock.send(json.dumps(data).encode('utf8')) 81 is_exist = self.sock.recv(1024).decode('utf8') 82 has_send = 0 83 if is_exist == '800': 84 # 文件不完整 85 choice = input('the file exist,but not enough,is continue?[Y/N]').strip() 86 if choice.upper() == 'Y': 87 self.sock.sendall('Y'.encode('utf8')) 88 continue_position = self.sock.recv(1024).decode('utf8') 89 has_send += int(continue_position) 90 else: 91 self.sock.sendall('N'.encode('utf8')) 92 elif is_exist == '801': 93 # 文件完全存在 94 print('the file exist') 95 return 96 else: 97 pass 98 f = open(local_path, 'rb') 99 f.seek(has_send)100 while has_send < file_size:101 data = f.read(1024)102 self.sock.sendall(data)103 has_send += len(data)104 self.show_progress(has_send, file_size)105 f.close()106 print('successfully upload!')107 108 def show_progress(self, has, total):109 rate = float(has)/float(total)110 rate_num = int(rate*100)111 if self.last != rate_num:112 sys.stdout.write('%s%% %s\r' % (rate_num, '#'*rate_num))113 self.last = rate_num114 115 def ls(self, *cmd_list):116 data = {117 'action': 'ls'118 }119 self.sock.sendall(json.dumps(data).encode('utf8'))120 data = self.sock.recv(1024).decode('utf8')121 print(data)122 123 def cd(self, *cmd_list):124 data = {125 'action': 'cd',126 'dirname': cmd_list[1]127 }128 self.sock.sendall(json.dumps(data).encode('utf8'))129 data = self.sock.recv(1024).decode('utf8')130 self.current_dir = os.path.basename(data)131 132 def mkdir(self, *cmd_list):133 data = {134 'action': 'mkdir',135 'dirname': cmd_list[1]136 }137 self.sock.sendall(json.dumps(data).encode('utf8'))138 data = self.sock.recv(1024).decode('utf8')139 140 def authenticate(self):141 if self.options.username is None or self.options.password is None:142 username = input('username:')143 password = input('password:')144 return self.get_auth_result(username, password)145 return self.get_auth_result(self.options.username, self.options.password)146 147 def response(self):148 data = self.sock.recv(1024).decode('utf8')149 data = json.loads(data)150 return data151 152 def get_auth_result(self, username, password):153 data = {154 'action': "auth",155 'username': username,156 'password': password157 }158 self.sock.send(json.dumps(data).encode('utf8'))159 response = self.response()160 print('response:', response['status_code'])161 if response['status_code'] == 254:162 self.username = username163 self.current_dir = username164 print(STATUS_CODE[response['status_code']])165 return True166 else:167 print(STATUS_CODE[response['status_code']])168 169 170 ch = ClientHandler()171 ch.interactive()
ftp_client.py
十二 进程与线程
1、为什么要有操作系统?
现代计算机系统是由一个或者多个处理器、内存、硬盘、打印机、键盘、鼠标和显示器等组成的。网络接口以及各种其他输入/输出设备组成的复杂系统,每位程序员不可能掌握所有系统实现的细节,并且管理优化这些部件是一件具有挑战性极强的工作。所以,我们需要为计算机安装一层软件,成为操作系统,任务就是用户程序性提供一个简单清晰的计算机模型,并管理以上设备。
定义:操作系统是一个用来协调、管理和控制计算机硬件和软件资源的系统程序,它位于硬件和应用程序之间。程序是运行在系统上的具有某种功能的软件,比如:浏览器,音乐播放器等。
操作系统内部的定义:操作系统的内核是一个管理和控制程序,负责管理计算机的所有物理资源,其中包括:文件系统、内存管理、设备管理、进程管理。
2、什么是进程?
假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源。是不是在程序A读取数据的过程中,让程序B去执行,当程序A读取完数据之后,让程序B暂停,然后让程序A继续执行?当然没问题,但这里有一个关键词:切换;既然是切换,那么这就涉及到了状态的保存,状态的恢复,加上程序A与程序B所需要的系统资源(内存,硬盘,键盘等等)是不一样的。自然而然的就需要有一个东西去记录程序A和程序B分别需要什么资源,怎样去识别程序A和程序B等等,所以就有了一个叫进程的抽象。
定义:
进程就是一个程序在一个数据集上的一次动态执行过程。进程一般由程序、数据库、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成。数据集则是程序在执行过程中所需要使用的资源。进程控制块用来记录的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
本质上就是一段程序的运行过程(抽象的概念)
3、什么是线程?
线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷,让进程内并发成为可能。
4、进程与线程区别
1、一个程序至少有一个进程,一个进程至少有一个线程(进程可以理解成线程的容器)
2、进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
3、线程在执行过程中与进程还是有区别的,每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
4、进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位;线程是进程的一个实体,是CPU调度和分源的基本单位,它是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源,只拥有一点运行中必不可少的资源(如程序计数器,一组寄存器和钱),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。一个进程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。
5、线程:最小的执行单元(实例);进程:最小的资源单位
5、Python的GIL(全局解释锁;Global Interpreter Lock)
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)
上面的核心意思:无论你启多少个线程,你有多少个CPU,Python在执行的时候会淡定的在同一时刻只允许一个线程运行。
6、 线程的两种调用方式
threading 模块建立在thread 模块之上。thread模块以低级、原始的方式来处理和控制线程,而threading 模块通过对thread进行二次封装,提供了更方便的api来处理线程。
调用方式:
方式一、
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import threading 4 import time 5 6 7 def music(): 8 print('begin to listen % s' % time.ctime()) 9 time.sleep(3)10 print('stop to listen %s' % time.ctime())11 12 13 def game():14 print('begin to play game % s \r\n' % time.ctime())15 time.sleep(5)16 print('stop to play game %s \r\n' % time.ctime())17 18 19 threads = []20 t1 = threading.Thread(target=music)21 t2 = threading.Thread(target=game)22 threads.append(t1)23 threads.append(t2)24 if __name__ == '__main__':25 # join()功能:在子线程完成运行之前,这个子线程的父线程讲一直被阻塞26 # t1 = threading.Thread(target=music)27 # t2 = threading.Thread(target=game)28 # t1.start()29 # t2.start()30 #31 # t1.join()32 # t2.join()33 # print('end')34 35 # setDaemon():将线程生命为守护线程36 t2.setDaemon(True) # 注:一定要在start之前设置37 for t in threads:38 t.start()39 print('end')
threading
方式二、
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import threading 4 import time 5 6 7 class MyThread(threading.Thread): 8 def __init__(self, num): 9 threading.Thread.__init__(self)10 self.num = num11 12 def run(self): # 定义每个线程要运行的函数13 14 print("running on number:%s" % self.num)15 16 time.sleep(3)17 18 19 if __name__ == '__main__':20 t1 = MyThread(1)21 t2 = MyThread(2)22 t1.start()23 t2.start()24 25 print("ending......")
继承方式调用线程
join():在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
setDaemon(True):
将线程生命为守护线程,必须在start()方法调用之前设置,如果不设置为守护线程,程序会被无限挂起。这个方法基本和join是相反的。当我们在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程就分兵两路,分别运行,那么当主线程完成想退出时,会验证子线程是否完成。如果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是,只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以用setDaemon方法了。
其他方法:
1 # run():用于表示线程活动的方法 2 # start():启动线程活动 3 # isAlive():返回线程是否活动的,返回布尔值,True/False 4 # getName():返回线程名字 5 # setName():设置线程名字 6 7 threading模块提供的一些方法: 8 # threading.currentThread():返回当前的线程变量 9 # threading.enumerate():返回一个包含正在运行的线程的list。正在运行指线程启动后-结束前,不包括启动前和终止后的线程10 # threading.activeCount():返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import threading 4 import time 5 6 7 def music(): 8 print('begin to listen % s' % time.ctime()) 9 time.sleep(3)10 print('stop to listen %s' % time.ctime())11 12 13 def game():14 print('begin to play game % s \r\n' % time.ctime())15 time.sleep(5)16 print('stop to play game %s \r\n' % time.ctime())17 18 19 threads = []20 t1 = threading.Thread(target=music)21 t2 = threading.Thread(target=game)22 threads.append(t1)23 threads.append(t2)24 if __name__ == '__main__':25 # join()功能:在子线程完成运行之前,这个子线程的父线程讲一直被阻塞26 # t1 = threading.Thread(target=music)27 # t2 = threading.Thread(target=game)28 # t1.start()29 # t2.start()30 #31 # t1.join()32 # t2.join()33 # print('end')34 35 # setDaemon():将线程生命为守护线程36 t2.setDaemon(True) # 注:一定要在start之前设置37 for t in threads:38 t.start()39 print(t.getName())40 print('count:', threading.activeCount())41 while threading.activeCount() == 3:42 print('end')
其他方法演示
7、同步锁(lock)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import threading 4 import time 5 num = 100 6 7 8 def sub(): 9 global num10 print('ok')11 lock.acquire() # 加锁12 temp = num13 time.sleep(0.001)14 num = temp-115 lock.release() # 释放锁16 17 18 li = []19 lock = threading.Lock()20 for i in range(100):21 t1 = threading.Thread(target=sub)22 t1.start()23 li.append(t1)24 for l in li:25 l.join()26 print(num)
注:多个线程都在同时操作同一个共享资源,所以造成了资源破坏(join会造成串行,失去线程的意义),可以通过同步锁来解决这种问题。
作者:陈彦斌
原文出处:https://www.cnblogs.com/chenyanbin/p/10406263.html
Python 之网络式编程 (上):https://www.imooc.com/article/281284
Python 之网络式编程 (下):https://www.imooc.com/article/281286
共同学习,写下你的评论
评论加载中...
作者其他优质文章