app自動化11 線程實現多個腳本在多個手機運行


線程

多任務簡單介紹

- 有很多事情在現實生活的場景中是同時進行的,比如開車的時候 手和腳共同來駕駛汽車,再比如唱歌跳舞也是同時進行的。
- 多任務,就是能夠在同一時間同時進行多個任務。
這樣同時進行多個任務,有一個極大的好處,那就是節省時間
代碼舉例
import time
import threading

def sing():
    for i in range(5):
        print("唱歌")
        time.sleep(1)

def dance():
    for i in range(5):
        print("跳舞")
        time.sleep(1)

t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)

t1.start()
t2.start()
import time
import threading

def sing():
    for i in range(5):
        print("唱歌")
        time.sleep(1)

def dance():
    for i in range(5):
        print("跳舞")
        time.sleep(1)

sing()
dance()
第一段代碼開啟3個線程,分別是主線程,子線程t1,子線程t2,耗時一共是5秒
第二段代碼開啟1個線程,那就是主線程,耗時一共是10秒

為什么第一段代碼耗時只要5秒,而第二段代碼耗時要10秒呢?

下面就由sunt來為大家說下原因吧,先分析第一段代碼:
主線程先開始運行,然后讓兩個小弟,也就是子線程t1,t2。分別去執行sing()和dance()代碼,這兩個小弟是並行執行的,並不是說小弟t1先執行完,
小弟t2才去執行,而是兩個小弟同時執行,故耗時為5秒,圖解如下:
打印出來結果:
唱歌
跳舞
跳舞
唱歌
跳舞
唱歌
跳舞
唱歌
跳舞
唱歌
這是因為當他們從休眠到喚醒是同時的,故資源掠奪的不確定性,有可能跳舞先執行,也有可能唱歌先執行,不過一定是成對出現的。
並行執行耗時總時間為5秒。

接下來分析第二段代碼:
主線程先開始執行,然后主線程執行sing()代碼塊,等待sing()代碼塊執行完之后,才開始執行dance()代碼塊。故耗時為sing()代碼塊
的時間加dance()代碼塊的時間,一共為10秒。圖解如下:

多任務的原理

什么叫“多任務”呢?簡單地說,就是操作系統可以同時運行多個任務。打個比方,你一邊在用瀏覽器上網,一邊在聽MP3,一邊在用Word趕作業,這就是多任務,至少同時有3個任務正在運行。還有很多任務悄悄地在后台同時運行着,只是桌面上沒有顯示而已。
單核cpu工作原理
- 現在,多核CPU已經非常普及了,但是,即使過去的單核CPU,也可以執行多任務。由於CPU執行代碼都是順序執行的,那么,單核CPU是怎么執行多任務的呢?
- 答案就是操作系統輪流讓各個任務交替執行,任務1執行0.01秒,切換到任務2,任務2執行0.01秒,再切換到任務3,執行0.01秒……這樣反復執行下去。實際上看,每個任務都是交替執行的,但是,由於CPU的執行速度實在是太快了,我們感覺就像所有任務都在同時執行一樣。
- 真正的並行執行多任務只能在多核CPU上實現,但是,由於任務數量遠遠多於CPU的核心數量,所以,操作系統也會自動把很多任務輪流調度到每個核心上執行。
多核cpu工作原理
和單核類似,相當於多了一個干活的人。
並發:指的是任務數多於cpu核數,通過操作系統的各種任務調度算法,實現用多個任務“一起”執行
(實際上總有一些任務不在執行,因為切換任務的速度相當快,看上去一起執行而已)
並行:指的是任務數小於等於cpu核數,即任務真的是一起執行的
- 並行和並發都算是多任務,但並行實際上才是真正的多任務,並發是假的。

線程的兩張創建方式

- 直接使用threading模塊的Thread類,指定要執行的方法,再調用start
- 使用繼承的方式,繼承Thread類,重新run方法,創建這個對象后,再調用start

查看當前程序線程數量

threading.enumerate()
- 獲取所有線程,返回的是一個列表。
- 如果需要個數,使用len(threading.enumerate())

為子線程傳遞參數

target方式
import time
import threading 

def sing(nums):
    for i in range(nums):
        print("唱歌")
        time.sleep(1)

def dance():
    for i in range(5):
        print("跳舞")
        time.sleep(1)

t1 = threading.Thread(target=sing, args=(3,))
t2 = threading.Thread(target=dance)

t1.start()
t2.start()
類繼承方式
import threading

class Work1(threading.Thread):

    def __init__(self, nums):
        super().__init__()
        self.nums = nums

    def run(self):
        for i in range(self.nums):
            print("haha")


def main():
    w = Work1(2)
    w.start()

if __name__ == "__main__":
    main()

Appium多端口

目標,讓一個腳本去跑到多台手機。
注意點: appium sever端口要不同,開啟多個。bootstrap端口要不同,開啟多個。udid需要指定,udid表示設備的唯一表示符號,通過 adb devices 查看。 前半部分都是,比如模擬器的(192.168.57.101:5555)。
appium server  和  bootstrap 和 udid 應該是成對出現的。
命令:
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
-p 表示 appium的端口
-bp 表示 bootstrap的端口
-U 表示設備的標識符
修改init_driver讓,init_driver接受port的參數。並且進行對應的連接。
記得,創建的是不同的driver對象。
因為如果使用threading.Thread的這種形式,需要指定執行的函數,所以,把需要執行的代碼,封裝成一個函數。然后使用
    ports = ["4723", "4725"]

    for i in ports:
        threading.Thread(target=do, args=(i,)).start()
來去執行創建多個driver並且進行腳本的操作。
下面看圖解就知道appium多端口的工作原理了。
依照上圖可以知道,如果要想讓一段腳本操作兩個手機,那么我要做的就是,開啟兩個appium服務和兩個bootstrap服務,並且端口號不能相同,
appium和bootstrap是一對,並且有兩個手機,還要指定手機設備號,故命令如下
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
    
appium -p 4725 -bp 4726 -U 192.168.57.102:5555

代碼實現

命令行先啟動appium並指定端口,並指定bootstrap端口和手機設備號
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
    
appium -p 4725 -bp 4726 -U 192.168.57.102:5555
base_driver.py
from appium import webdriver


def init_driver(port="4723"):
    # server 啟動參數
    desired_caps = dict()
    # 設備信息
    desired_caps['platformName'] = 'Android'
    desired_caps['platformVersion'] = '5.1'
    desired_caps['deviceName'] = '192.168.164.101:5555'
    # app信息
    desired_caps['appPackage'] = 'com.android.settings'
    desired_caps['appActivity'] = '.Settings'
    # 中文
    desired_caps['unicodeKeyboard'] = True
    desired_caps['resetKeyboard'] = True
    # 不重置應用
    desired_caps['noReset'] = True
    # toast
    # desired_caps['automationName'] = 'Uiautomator2'
    # 聲明對象
    driver = webdriver.Remote('http://localhost:' + port + '/wd/hub', desired_caps)
    return driver
login_page.py
from base_action import BaseAction


class LoginPage(BaseAction):

    pass
demo.py
import threading

from selenium.webdriver.common.by import By

from base_driver import init_driver
from base_action import BaseAction
from login_page import LoginPage


def do(port):
    driver = init_driver(port)
    login_page = LoginPage(driver)
    if "4723" == port:
        login_page.click((By.XPATH, "text,更多"))
    else:
        login_page.click((By.XPATH, "text,WLA"))

def main():
    //根據ports不同,driver可以連接不同的手機
    ports = ["4723", "4725"]

    for i in ports:
        threading.Thread(target=do, args=(i,)).start()

if __name__ == '__main__':
    main()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM