Kann Applescript Multithreading sein?


7

Ich schreibe ein Applescript für Spotify, das zwei Dinge tun soll:

  1. Protokolliere jedes neu gespielte Lied.
  2. Überprüfen Sie alle N Sekunden, welches Audiogerät verwendet wird.

Ich mache (1) durch eine einfache Schleife, die prüft, wie viel von der Spur übrig bleibt, und verwende diesen Wert dann in einer Verzögerungsanweisung in der Schleife (nicht erforderlich, um die Schleife mit voller Geschwindigkeit auszuführen). N ist jedoch normalerweise viel niedriger als die verbleibende Zeit der aktuellen Spur. Daher möchte ich, dass Aufgabe (2) in einer separaten Schleife mit N-0,5 als Verzögerungswert ausgeführt wird. Grundsätzlich möchte ich Schleifen gleichzeitig mit demselben Skript ausführen. Ist das möglich?

(Natürlich könnte ich zwei separate Skripte verwenden, aber ich muss diese Lösung verteilen, wenn sie fertig ist. Daher ist eine geringere visuelle Komplexität - dh zwei Skripte, die gleichzeitig ausgeführt werden und Speicherplatz im Dock beanspruchen, gestartet werden müssen usw. - besser.)


In diesem Fall sehen Sie sich Ereignisse an, bei denen das Starten eines neuen Songs ein Applescript auslöst - auch ein Ereignis, wenn ein Soundgerät geändert wird
user151019,

Wie sehe ich Ereignisse? Ich interessiere mich nicht nur für Spotify, sondern auch für einige andere Anwendungen, einschließlich iTunes, Pages und Chrome.
DB

Antworten:


2

Nicht einfach. Das Konzept von Prozessen und Threads ist in AppleScript nicht enthalten.

Sie benötigen ein anderes Tool für diesen Job. Swift ist vielleicht gut, es sei denn, Sie suchen nach Python oder etwas Etablierterem.


2

Sprachgrenzen

Ab macOS 10.13 unterstützt AppleScript Multithreading in einem einzelnen Skript nicht mehr. Die Verwendung NSThreadin einem AppleScript scheint möglich zu sein , dies ist jedoch komplex und führt zu einer zweiten Einschränkung, der der Anwendung, mit der interagiert wird.

Anwendungsgrenzen

Zusätzlich zu der AppleScript-Sprache selbst, die keine Threads nativ darstellt, ist es unwahrscheinlich, dass die aufgerufene Anwendung mit AppleEvents in einer Thread-optimalen Weise umgeht. AppleEvents werden von macOS in einer FIFO-Reihenfolge (First-In First-Out) zur Verarbeitung durch die Anwendung in die Warteschlange gestellt.

Die Anwendung kann Antworten auf lange laufende AppleEvents verschieben, dies erfordert jedoch zusätzliches Engineering, das nur wenige Anwendungen implementieren. Die meisten Anwendungen werden blockiert, bis das AppleEvent verarbeitet wird, bevor das nächste AppleEvent angezeigt wird.

Dies bedeutet, dass ein AppleScript mit mehreren Threads, das mit einer einzelnen Anwendung kommuniziert, wahrscheinlich nicht die erwarteten Leistungssteigerungen für den Aufwand sehen würde.

Einzelne Ereignisschleife?

Sie können sich dem Problem mit einer einzelnen Schleife nähern, die sich mit mehreren Ereignissen befasst. Die einzelne Schleife könnte N Sekunden lang schlafen, aufwachen und die anstehenden entsprechenden Aufgaben erledigen.

Die Antwort von Piyomaru zeigt einen Weg, einen ereignisbasierten Ansatz zu implementieren. Dieser Ansatz ist nicht multithreaded oder parallel. Es ist eine ereignisgesteuerte Schleife.


AppleScript unterstützt NSThread jetzt nativ. Der Skript-Editor sagt "AppleScript 2.5 (Thread Safe)" in seinem Popup-Selektor für die OSA-Sprache (dies wird im Multithread aufgerufen).
Piyomaru

Unterstützung NSThreadbedeutet nicht, dass das Skript mit einem Thread versehen ist. Weitere Informationen finden Sie unter Gewindesicherheit .
Graham Miln

In der Tat kann AppleScript jetzt Threads über NSThread wie folgt generieren. piyocast.com/as/archives/4897
Piyomaru

Das ist gut zu wissen. Ich habe meine Antwort aktualisiert. Ihr vorgeschlagenes Skript wird nicht verwendet NSThread. Kann es zum Threading geändert werden?
Graham Miln

Mac OS X und seine API Cocoa verwenden in diesem Fall Benachrichtigungen. Es hat keinen Sinn, Thread zu verwenden.
Piyomaru

1

AppleScript unterstützt jetzt Multithreading (macOS 10.10 oder höher). Und ursprünglich hat es seit 1993 eine Timer-Interrupt-Funktion ( on idleTimer-Ereignishandler arbeitet gleichzeitig in einem einzelnen AppleScript).

Ich habe einige AppleScripts mit iTunes geschrieben, wie Sie geschrieben haben. AppleScript kann Delegierte erstellen und Ereignisse anderer Anwendungen empfangen.

Dieses Beispiel-AppleScript kann die Änderung des Wiedergabestatus von iTunes empfangen. Sobald das Skript im Skript-Editor ausgeführt wird, empfängt es das Änderungsereignis von iTunes und zeigt den Namen des Titels im MacOS-Benachrichtigungsdialog an.

-- Created 2017-10-13 by Takaaki Naganoya
-- 2017 Piyomaru Software

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSDistributedNotificationCenter : a reference to current application's NSDistributedNotificationCenter

on run
    NSDistributedNotificationCenter's defaultCenter()'s addObserver:me selector:"statusChanged:" |name|:"com.apple.iTunes.playerInfo" object:(missing value)

end run

on statusChanged:sender
    tell application id "com.apple.iTunes"
        try
            tell current track
                set anAlbum to album
                set aName to name
                set anArtist to album artist
                set aRating to rating
            end tell
        on error
            return
        end try
    end tell
    display notification aName
end statusChanged:

Der Punkt ist also, dass die Spotify-Anwendung eine solche Funktion wie iTunes bereitstellen kann oder nicht.


1
Vielen Dank für Ihre Antwort. Denken Sie, Sie könnten dem Code einige Kommentare hinzufügen, um zu erklären, wie es funktioniert? Es ist nicht offensichtlich / ich bin nicht gut genug in Applescript, um es im Detail zu verfolgen.
DB

Ich bin bereit, verschiedene Dienstleistungen anzubieten, die für Ihre Garantie geeignet sind :-)
Piyomaru

0

Ich würde vorschlagen, dies in JavaScript anstatt in AppleScript zu schreiben. JavaScript ist eine unterstützte Sprache für Apple Events Scripting. JavaScript ist Single-Threaded, aber es ist viel einfacher, nicht blockierenden asynchronen Code zu schreiben.

setInterval(function() {
    console.log('Do something in the closure function here');
}, 3000);

1
Willkommen bei Ask Different! Während die Verwendung von JavaScript eine Möglichkeit sein kann, ist IMO, ohne ein funktionierendes Beispiel anzugeben, nur ein Kommentar, keine Antwort. Wenn Sie die Verwendung einer Sprache vorschlagen, die im OP oder in den Tags nicht erwähnt wird, sollte eine gute Antwort in der Regel zeigen, wie das Ziel erreicht werden kann, und nicht nur die Verwendung einer Sprache vorschlagen, die im OP nicht erwähnt wird.
user3439894

Ich spreche kein Javascript (nun, ich kann es auf einer extrem einfachen Ebene lesen, da ich Java und etwas C kenne). Können Sie mir ein Beispiel geben?
db

Sie können eine setInterval-Funktion verwenden, um alle drei Sekunden eine Aufgabe auszuführen. Es ist jedoch besser, sich an ein Ereignis zu binden. Es ist fast 20 Jahre her, dass ich Apple Events-Skripte erstellt habe, aber dies sollte möglich sein. Hier ist ein Codebeispiel für setInterval. // Alle drei Sekunden auf etwas prüfen setInterval (function () {// Der Code in dieser Funktion prüft jedes Mal, wenn setInterval ausgelöst wird. Console.log ('etwas prüfen');}, 3000);
David Fekke

1
Kommentare werden nicht von Suchmaschinen indiziert und können und werden manchmal gelöscht. Daher ist es besser, wenn Sie relevante Informationen zur tatsächlichen Antwort über den Bearbeitungslink unten links in der Antwort hinzufügen , nicht in Kommentaren.
user3439894
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.