天天看點

python 闖關之路四(下)(并發程式設計與資料庫程式設計)

并發程式設計重點:

并發程式設計:線程、程序、隊列、IO多路模型

作業系統工作原理介紹、線程、程序演化史、特點、差別、互斥鎖、信号、
事件、join、GIL、程序間通信、管道、隊列。

生産者消息者模型、異步模型、IO多路複用模型、select\poll\epoll 高性
能IO模型源碼執行個體解析、高并發FTP server開發
      

1、請寫一個包含10個線程的程式,主線程必須等待每一個子線程執行完成之後才結束執行,每一個子線程執行的時候都需要列印目前線程名、目前活躍線程數量;

from threading import Thread,currentThread,activeCount
import time
def task(n):
    print('線程名:%s----%s'%(currentThread().name,n))
    time.sleep(1)
    print('數量:%s'%activeCount())
    
if __name__ == "__main__":
    t_li = []
    for i in range(10):
        t = Thread(target=task,args=(i,))
        t.start()
        t_li.append(t)
    for t in t_li:
        t.join()
        
    print('主,end----')
      

2、請寫一個包含10個線程的程式,并給每一個子線程都建立名為"name"的線程私有變量,變量值為“james”;

from threading import Thread
def task(name):
    print('%s is running'%name)
    print('end ---')
    
if __name__ == "__main__":
    for i in range(10):
        t = Thread(target=task,args=('james_%s'%i,))
        t.start()
        
    print('主 end ---')
      

3、請使用協程寫一個消費者生産者模型;

協程知識點:https://www.cnblogs.com/wj-1314/p/9040121.html

協程:單線程下,無法利用多核,可以是一個程式開多個程序,每個程序開啟多個線程,每隔線程開啟協程;

  協程指的是單個線程,因而一旦協程出現阻塞,将會阻塞整個線程。

def consumer():
    while True:
        x = yield
        print('消費:', x)
        
def producter():
    c = consumer()
    next(c)
    for i in range(10):
        print('生産:', i)
        c.send(i)
        
producter()
      

4、寫一個程式,包含十個線程,子線程必須等待主線程sleep 10秒鐘之後才執行,并列印目前時間;

from threading import Thread,Event
import time
import datetime
def task():
    # while not event.is_set():
    #     print('...')
    print('...')
    event.wait(10)
    print('time:',datetime.datetime.now())
    
if __name__ == '__main__':
    event = Event()
    for i in range(10):
        t = Thread(target=task)
        t.start()
        
    time.sleep(10)
    event.set()
      

5、寫一個程式,包含十個線程,同時隻能有五個子線程并行執行;

from threading import Thread,Semaphore,currentThread
import time
def task(n):
    sm.acquire()
    print('%s---'%n,currentThread().name)
    time.sleep(1)
    print('end----')
    sm.release()
    
if __name__ == '__main__':
    sm = Semaphore(5)
    for i in range(10):
        t = Thread(target=task,args=(i,))
        t.start()
      

6、寫一個程式 ,包含一個名為hello的函數,函數的功能是列印字元串“Hello, World!”,該函數必須在程式執行30秒之後才開始執行(不能使用time.sleep());

from threading import Timer
def hello(name):
    print('%s say '%name,'Hello World!')
    
if __name__ == "__main__":
    t = Timer(5,hello,args=('james',))
    t.start()
      

7、寫一個程式,利用queue實作程序間通信;

from multiprocessing import Process,Queue,current_process
import time
def consumer(q):
    while True:
        res = q.get()
        if not res:break
        print('消費了:',res,'--',current_process().name)
        
def producter(q):
    for i in range(5):
        print('生産:',i)
        time.sleep(1)
        q.put(i)
        
if __name__ == "__main__":
    q = Queue()
    p1 = Process(target=producter,args=(q,))
    c1 = Process(target=consumer,args=(q,))
    c2 = Process(target=consumer,args=(q,))
    p1.start()
    c1.start()
    c2.start()
  
    p1.join()
    q.put(None)
    q.put(None)
    print('主')
    
# JoinableQueue
from multiprocessing import Process,JoinableQueue,current_process
import time
def consumer(q):
    while True:
        res = q.get()
        print('消費了:',res,'--',current_process().name)
        q.task_done()
        
def producter(q):
    for i in range(5):
        print('生産:',i,'--',current_process().name)
        time.sleep(1)
        q.put(i)
    q.join()
    
if __name__ == "__main__":
    q = JoinableQueue()
    p1 = Process(target=producter,args=(q,))
    p2 = Process(target=producter, args=(q,))
    c1 = Process(target=consumer,args=(q,))
    c2 = Process(target=consumer,args=(q,))
    p1.start()
    p2.start()
    
    c1.daemon = True
    c2.daemon = True
    c1.start()
    c2.start()
    
    p1.join()
    p2.join()
    print('主')
      

8、寫一個程式,利用pipe實作程序間通信;

from multiprocessing import Process,Pipe
def task(conn):
    conn.send('hello world')
    conn.close()
    
if __name__ == "__main__":
    parent_conn,child_conn = Pipe()
    p = Process(target=task,args=(child_conn,))
    p.start()
    p.join()
    print(parent_conn.recv())
      

9、使用selectors子產品建立一個處理用戶端消息的伺服器程式;

# server  blocking IO  
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
    conn,addr = server.accept()
    print(addr)
    while True:
        try:
            data = conn.recv(1024)
            if not data: break
            conn.send(data.upper())
        except Exception as e:
            print(e)
            break
            
# server  IO多路複用 selectors 會根據作業系統選擇select poll epoll           
import socket
import selectors
sel = selectors.DefaultSelector()
def accept(server_fileobj,mask):
    conn,addr = server_fileobj.accept()
    print(addr)
    sel.register(conn,selectors.EVENT_READ,read)
    
def read(conn,mask):
    try:
        data = conn.recv(1024)
        if not data:
            print('closing..',conn)
            sel.unregister(conn)
            conn.close()
            return
        conn.send(data.upper())
    except Exception:
        print('closeing...',conn)
        sel.unregister(conn)
        conn.close()
        
server_fileobj = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_fileobj.bind(('127.0.0.1',8080))
server_fileobj.listen(5)
server_fileobj.setblocking(False)
sel.register(server_fileobj,selectors.EVENT_READ,accept)
while True:
    events = sel.select()
    for sel_obj,mask in events:
        callback = sel_obj.data
        callback(sel_obj.fileobj,mask)
        
# client
# -*- coding:utf-8 -*-
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
    msg = input('>>>:').strip()
    if not msg:continue
    client.send(msg.encode('utf-8'))
    data = client.recv(1024)
    print(data.decode('utf-8'))
      

10、使用socketserver建立伺服器程式時,如果使用fork或者線程伺服器,一個潛在的問題是,惡意的程式可能會發送大量的請求導緻伺服器崩潰,請寫一個程式,避免此類問題;

# server socketserver 子產品内部使用IO多路複用 和多程序/多線程
import socketserver
class Handler(socketserver.BaseRequestHandler):
    def handle(self):
        print('new connection:',self.client_address)
        while True:
            try:
                data = self.request.recv(1024)
                if not data:break
                print('client data:',data.decode())
                self.request.send(data.upper())
            except Exception as e:
                print(e)
                break
                
if __name__ == "__main__":
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),Handler)
    server.serve_forever()
      

11、請使用asyncio實作一個socket伺服器端程式;

 12、寫一個程式,使用socketserver子產品,實作一個支援同時處理多個用戶端請求的伺服器,要求每次啟動一個新線程處理用戶端請求;

socketserver子產品類介紹
      SocketServer内部使用 IO多路複用 以及 “多線程” 和 “多程序” ,
進而實作并發處理多個用戶端請求的Socket服務端。即:每個用戶端請求
連接配接到伺服器時,Socket服務端都會在伺服器是建立一個“線程”或者“進 程”
 專門負責處理目前用戶端的所有請求。
        socketserver子產品可以簡化網絡伺服器的編寫,python把網絡服務抽
象成兩個主要的類,一個是server類,用于處理連接配接相關的網絡操作,另一個
是RequestHandler類,用于處理資料相關的操作。并且提供兩個Mixln類,
用于擴充server,實作多程序或者多線程。
      

  

import socketserver
import threading


class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            self.data = self.request.recv(1024).decode()
            print(self.data)
            self.request.send(self.data.upper().encode())
        
        
if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('127.0.0.1', 9999), MyServer)
    t = threading.Thread(target=server.serve_forever)
    t.start()
      

資料庫重點:

1、資料庫介紹、類型、特性
2、MySQL資料庫安裝、連接配接、啟動、停止
3、表字段類型介紹、主鍵限制、表建立語句
4、常用增删改查語句、分組、聚合
5、外鍵管理、unique字段、表結構修改文法
6、跨表查詢,inner join、left join、right join、full join文法
7、複雜SQL語句如group by、子查詢、函數的使用
8、索引原理及作用、普通索引、多列索引、唯一索引、全文索引等
9、基于hash&b+樹索引的實作原理,索引的優缺點剖析
10、事務原理,ACID特性,應用場景講解
11、事務復原
12、觸發器的特性,應用場景
13、觸發器的增删改查方法
14、存儲過程的作用及應用場景
15、建立存儲過程,參數傳遞,流程控制語句if\while\repeat\loop等,動态SQL的建立
16、視圖的作用及使用場景,視圖的增删改查
17、資料庫權限管理,使用者管理
18、資料庫備份指令及工具講解
19、基于不同業務的資料庫表結構設計、性能優化案例
20、pymysql子產品介紹和使用
      

修改表結構的文法

文法:
1. 修改表名
      ALTER TABLE 表名 
                          RENAME 新表名;

2. 增加字段
      ALTER TABLE 表名
                          ADD 字段名  資料類型 [完整性限制條件…],
                          ADD 字段名  資料類型 [完整性限制條件…];
      ALTER TABLE 表名
                          ADD 字段名  資料類型 [完整性限制條件…]  FIRST;
      ALTER TABLE 表名
                          ADD 字段名  資料類型 [完整性限制條件…]  AFTER 字段名;

3. 删除字段
      ALTER TABLE 表名 
                          DROP 字段名;

4. 修改字段
      ALTER TABLE 表名 
                          MODIFY  字段名 資料類型 [完整性限制條件…];
      ALTER TABLE 表名 
                          CHANGE 舊字段名 新字段名 舊資料類型 [完整性限制條件…];
      ALTER TABLE 表名 
                          CHANGE 舊字段名 新字段名 新資料類型 [完整性限制條件…];
      

1、建立一個表student,包含ID(學生學号),sname(學生姓名),gender(性别),credit(信用卡号),四個字段,要求:ID是主鍵,且值自動遞增,sname是可變長字元類型,gender是枚舉類型, credit是可變長字元類型;

create table student(
    ID int primary key auto_increment,
    sname varchar(16) not null,
    gender enum('male','female') not null default 'female',
    credit varchar(32)
);
      

2、在上面的student表中增加一個名為class_id的外鍵,外鍵引用class表的cid字段;

create table class(
    cid int primary key auto_increment,
    cname varchar(16) not null
);
  
alter table student add class_id int not null;
alter table student add foreign key(class_id) references class(cid) on delete cascade on update cascade;
      

3、向該表新增一條資料,ID為1,學生姓名為alex,性别女,修改ID為1的學生姓名為wupeiqi,删除該資料;

insert into class(cname) values
('一班'),
('二班');
insert into student values(1,'alex','female','12345',1);
update student set sname = 'wupeiqi' where id = 1;
delete from student where id = 1; 
      

4、查詢student表中,每個班級的學生數;

insert into student(sname,class_id) values
('james',1),
('durant',2),
('curry',3); 
select count(ID) from student;
      

5、修改credit字段為unique屬性;

alter table student modify credit varchar(32) not null unique;
      

6、請使用指令在你本地資料庫中增加一個使用者,并給該使用者授予建立表的權限;

grant create on *.* to 'james'@'localhost' identified by '123';       
      

7、請使用pymsql子產品連接配接你本地資料庫,并向student表中插入一條資料;

# _*_ coding: utf-8 _*_ 
# 7、請使用pymsql子產品連接配接你本地資料庫,并向student表中插入一條資料;
import pymysql
conn = pymysql.connect(
    host = '127.0.0.1',
    port = 3306,
    user = 'root',
    password = '******',
    db = 'test622',
    charset = 'utf8'
)
cursor = conn.cursor()
sql = "insert into student values(13,'park','男','123456',1)"
rows = cursor.execute(sql)

conn.commit()
cursor.close()
conn.close()
      

8、請使用mysqldump指令備份student表;

mysqldump -uroot -p123 db_bj student > /home/bj/桌面/myfile/student.sql
      

9、建立一張名為student_insert_log的表,要求每次插入一條新資料到student表時,都向student_insert_log表中插入一條記錄,記錄student_id, insert_time;

mysql> desc student;
+----------+-----------------------+------+-----+---------+----------------+
| Field    | Type                  | Null | Key | Default | Extra          |
+----------+-----------------------+------+-----+---------+----------------+
| ID       | int(11)               | NO   | PRI | NULL    | auto_increment |
| sname    | varchar(16)           | NO   |     | NULL    |                |
| gender   | enum('male','female') | NO   |     | female  |                |
| credit   | varchar(32)           | NO   | UNI | NULL    |                |
| class_id | int(11)               | NO   | MUL | NULL    |                |
+----------+-----------------------+------+-----+---------+----------------+
  
create table student_insert_log(
    student_id int not null,
    insert_time datetime not null
);
    
建立一個觸發器:
delimiter //
create trigger tri_after_insert_student after insert on student for each row
begin
    insert into student_insert_log values(new.ID,now());
end //
delimiter ;
    
insert into student(sname,credit,class_id) values ('alice','123',2);
insert into student(sname,credit,class_id) values 
('egon1','1234',1),
('egon2','12345',2);
    
mysql> select * from student;
+----+-------+--------+---------+----------+
| ID | sname | gender | credit  | class_id |
+----+-------+--------+---------+----------+
|  4 | alcie | female | 123456  |        1 |
|  7 | alcie | female | 1234567 |        1 |
|  8 | alice | female | 123     |        2 |
|  9 | egon1 | female | 1234    |        1 |
| 10 | egon2 | female | 12345   |        2 |
+----+-------+--------+---------+----------+
    
mysql> select * from student_insert_log;
+------------+---------------------+
| student_id | insert_time         |
+------------+---------------------+
|          8 | 2018-04-24 21:29:46 |
|          9 | 2018-04-24 21:32:05 |
|         10 | 2018-04-24 21:32:05 |
+------------+---------------------+
10、建立一張名為student_update_log的表,要求每次更新student表中的記錄時,都向student_update_log表中插入一條記錄,記錄student_id, update_time;
create table student_update_log(
    student_id int not null,
    update_time datetime
);  
    
建立一個觸發器
delimiter //
create trigger tri_after_update_student after update on student for each row
begin
    insert into student_update_log values(new.ID,now());
end //
delimiter ;
    
show triggers\G;
    
update student set sname = 'alex' where ID in (9,10);
mysql> select * from student;
+----+-------+--------+---------+----------+
| ID | sname | gender | credit  | class_id |
+----+-------+--------+---------+----------+
|  4 | alcie | female | 123456  |        1 |
|  7 | alcie | female | 1234567 |        1 |
|  8 | alice | female | 123     |        2 |
|  9 | alex  | female | 1234    |        1 |
| 10 | alex  | female | 12345   |        2 |
+----+-------+--------+---------+----------+
5 rows in set (0.00 sec)
    
mysql> select * from student_update_log;
+------------+---------------------+
| student_id | update_time         |
+------------+---------------------+
|          9 | 2018-04-24 21:47:24 |
|         10 | 2018-04-24 21:47:24 |
+------------+---------------------+
      

不經一番徹骨寒 怎得梅花撲鼻香

繼續閱讀