3 votos

La eliminación de numerosos página web de entradas de Contactos.aplicación con AppleScript extremadamente lento

Un problema con la sincronización de Outlook me dejó con cientos, si no miles, de los contactos duplicados. Después de la administración de combinar duplicados sin Contactos de estrellarse, me quedé con 177 contactos, la mayoría de los cuales con muchas repetir la página de inicio de entradas. En lugar de morir de aburrimiento de la eliminación de estos a mano, he reunido algunas de AppleScript para hacer esto por mí, pensando que iba a tomar un par de minutos. Ha sido una semana ahora el script empieza bastante bien, pero pronto se ralentiza continuamente y también toma más y más memoria del sistema, hasta el hilado beachball de doom aparece detener la secuencia de comandos. Uno de los problemas es que me parece que sólo será capaz de eliminar un contacto de la url de una en una en secuencia, en lugar de todos a la vez.

Así que la pregunta es, ¿qué tengo de malo hacer este script cerca de inútil? Podría tener algo que ver con la sincronización de iCloud? O AppleScript es inherentemente ineficiente? (La constante de ahorro, debido a que el azar veces el script podría dejar de funcionar.):

tell application "Contacts"
    activate
    with timeout of 72000 seconds
        set myPeople to people
        set numPeople to (count of myPeople)
        repeat with i from 1 to numPeople
            set myGuy to item i of myPeople
            set myGuyName to get name of myGuy
            set personUrls to (the urls of myGuy whose value contains "outlook")
            set urlNum to count of personUrls
            if urlNum > 0 then
                repeat with j from urlNum to 1 by -1
                    log ((time string of (current date)) & " – [" & i & "/" & numPeople & "] " & myGuyName & " (" & j & "/" & urlNum & "): " & (the label of item j of personUrls))
                    delete item j of personUrls
                    save
                end repeat
            else
                log "No problematic URLs found for " & myGuyName
            end if
            if note of myGuy is not missing value then set note of myGuy to ""
        end repeat
        save
        log "Final save"
    end timeout
    return
end tell

1voto

qarma Puntos 71

Que audaz afirmar AppleScript ser ineficientes (término vago) como una causa. Por supuesto, que muy bien podría ser un factor, pero se siente un poco raro decir que el guión es ineficiente, y lamentablemente así. No sé si esa es la única razón por la secuencia de comandos se ejecuta lentamente, pero es un buen lugar para empezar a hacer las correcciones, que describiré por la extracción de líneas problema en tu código:

⚠️ set myPeople to people

Redundante. Hay un pequeño punto en la asignación de un valor a una variable que no tiene intención de utilizar de una manera significativa (por ejemplo, para la manipulación de los datos sin cambiar la fuente, o, si usted realmente necesita, para hacer scripts más fáciles de leer o de depuración). En ningún otro lugar en su secuencia de comandos de hacer una referencia a myPeople, excepto para la otra línea que también es redundante. Por lo tanto, no pierdas una operación (y, potencialmente, de la memoria, pero no realmente en este caso en particular) la creación de una variable que no es necesario.

⭕️ set numPeople to (count of myPeople)

Redundante en principio (me tenga en cuenta que registro el valor de numPeople, a pesar de que sólo se utiliza para darle un índice de referencia, que usted no necesita saber; ver siguiente comentario).

⚠️ repeat with i from 1 to numPeople
       set myGuy to item i of myPeople

Ignorando por un momento el registro de la llamada que hace referencia a numPeople, entonces el propósito de la declaración numPeople es permitir que la iteración a través de una lista por medio de una variable de contador (i en su caso) que se utiliza para acceder a cada elemento a través de su índice (posición), es decir, item i of myPeople. Hay muchos casos donde esto sería muy apropiado, pero es más lento que dejar de AppleScript preocuparse acerca de cómo se accede a los elementos de la lista, que se puede tomar en las manos el uso de esta sintaxis: repeat with myGuy in people

⚠️ set urlNum to count of personUrls

Redundante, por la misma razón que el anterior. Como una nota adicional, creo personalmente que elija para evaluar el tamaño de una lista mediante el length de la propiedad. Esto no se aplica a las listas anidadas de listas para el que desea incluir profundamente los elementos anidados en el número final, pero ese no es el caso aquí.

Tan pronto como una secuencia de comandos se ha evaluado (recuperar) de un objeto, sus propiedades se han recuperado como parte de esa evaluación. length es una propiedad de un objeto de la lista, y es una simple, unarios valor ( integer), por lo que el acceso a ese valor siempre será rápida. count es un comando. Realiza algunos no revelado operaciones(s) y devuelve un valor. No sé lo que esas operaciones son, y se llevará a cabo en el C-nivel de idioma, así que probablemente (casi seguro) no son el retraso de esta secuencia de comandos de abajo del todo. Pero, en principio, es algo a tener en cuenta, ya que hay otras situaciones un comando y una propiedad aparentemente hacen lo mismo, pero la propiedad es demostrablemente más rápido.

No recuerdo ahora mismo.

⭕️ if urlNum > 0 then

Redundante, en principio. Hay un else cláusula que usted puede ser que insisten en mantener, pero la única cosa que lo hace para registrar el hecho de que no se ha hecho nada. Si alguien me preguntó cómo intencionalmente lento una secuencia de comandos de abajo porque es demasiado eficiente, esto podría ser uno de mis respuestas.

⚠️ repeat with j from urlNum to 1 by -1

Este está marcado por tanto el uso de una variable de contador, j, y por su posición dentro de la if bloque. Si urlNum se establece en 0, la repetición de bucle de escuchar nunca habría entrado, y el script seguirá ejecutando el código que sigue. Pero, como se pondrá de manifiesto, la totalidad de la repeat bloque es redunant.

⚠️ log ... (the label of item j of personUrls))
   delete item j of personUrls

Estoy cuestionando la necesidad de este log comando como un todo. Ciertamente no es tan contraproducente como la que mencioné antes, pero sí realizar una current date comando de llamada, y una búsqueda en la personUrls objeto de la lista.

  • En situaciones donde se requieren una variable de contador para iterar a través de una lista, hacer como hizo anteriormente, y declarar una variable a la que puede asignar el elemento de lista actual del valor, es decir, set hisURL to item j of personalUrls. En crudo términos, cada vez que le AppleScript para [el valor de] item j of..., se debe acceder a la lista de objetos y realizar una mirada hacia arriba, que es una operación relativamente costosa de realizar. La declaración de una variable significa que la búsqueda se realiza sólo una vez, entonces el valor de (una copia de la original) es almacenado en la memoria, para que la recuperación es rápida y fácil en términos computacionales.

Volviendo a el valor que se registra, su valor parece que se niega, por la supresión inmediata de los datos de direcciones URL. Me pregunto si usted podría tener sólo quería un medio de seguimiento en su secuencia de comandos habían alcanzado en su ejecución, los cuales no tienen que ser tan involucrado. El uso de su contador de variables, usted podría simplemente: log [j, i] (registro de sus límites superior una vez es suficiente, ya que los valores no cambian durante un bucle).

El delete comando, cuando se ve en el contexto de la repetición del bucle en el que se llama, va a ser de frenar las cosas un montón. Usted está iterando a través de cada elemento de una colección con el fin de eliminar...

⚠️ save

...luego de guardar los cambios. ¿Cómo puedo intencionalmente hacer mi script se ejecute tan lentamente como sea posible ? Me gustaría realizar una operación de guardar en la libreta de direcciones completa un número de veces igual a numPeople * urlNum. Este valor es al menos 177, pero en realidad múltiplos de este. El número total de veces que usted necesita para realizar el save de la operación, me imagino, sería de 1.

Los Efectos En Cadena:

Ahora sabemos que iterando PersonUrls no era necesario, toda la repeat bloque puede ser reemplazado con la línea: delete every url of myGuy whose....

  • Como algo a ser consciente de, cualquier secuencia de comandos que funciones anidadas repeat bucles va a ser ineficiente: el número de operaciones realizadas es un producto de cada una de las listas del tamaño.

De hecho, me tenga en cuenta que usted hace mención de intentar eliminar un contacto de la Url en masa, que no funciona para usted, lo que le obliga a hacerlo de forma iterativa. Sin embargo, como no proporcionar cualquier código que muestra los métodos que se trató de hacer la masa de la eliminación, no es posible ofrecer una idea de por qué ha fallado para usted.

La eliminación de la repeat bloque tiene un acumulado en beneficio de la negación de los padres if bloque, independientemente de mis anteriores comentarios.

  • Los condicionales pueden ser costosos expresiones a evaluar, en particular, la realización de 177 de ellos que nunca fueron necesarios.

El Refactorizado El Código:

Continuando hacia arriba a través de la secuencia de comandos, la variable anterior declaraciones de todos a ser redundante, lo que lleva a la eventual conclusión de que toda la secuencia de comandos es funcionalmente equivalente a:

use application "Contacts"

tell (a reference to every person)
    delete (its urls where the value contains "outlook")
    set its note to missing value
end tell

save

Sistema de información: AppleScript versión: 2.7 Sistema de versión: 10.13.6

¿Y Ahora Qué ?

Era su objetivo final para eliminar todas las Url que contengan "outlook", o ¿va a seguir con una "outlook" de la dirección URL para los contactos que tienen ellos ?

1voto

Nerdilicious Puntos 11

@CJK la respuesta no trabajo para mí, pero la respuesta dada en los Eventos de la pestaña de Editor de secuencias de Comandos me dio la base de una alternativa que parece funcionar como se pretende:

tell application "Contacts"
    delete (every url of every person whose value contains "outlook")
    set note of every person to missing value
    save
end tell

Añadido por @CJK en 2019-04-03:

En lugar de forzar AppleScript para enumerar every person en su libreta de direcciones de dos veces, que es, en términos generales, una costosa operación, almacenar una referencia a la colección en una variable, la cual se puede utilizar en varias ocasiones con mucha menos sobrecarga:

tell application "Contacts"
    set _everyone to a reference to every person
    set _homepages to a reference to _everyone's urls

    delete the _homepages where the value contains "outlook"
    set _everyone's note to missing value

    save
end tell

Sistema de información: AppleScript versión: 2.7 Sistema de versión: 10.13.6

Esto es lo que es devuelto por los Eventos o las Respuestas de la ficha cuando se ejecuta el original refactorizado el código:

tell application "Contacts"
    delete every url of every person whose value contains "outlook"
    set note of every person to missing value
end tell
tell application "Script Editor"
    save current application
end tell

Supongo que nada parece suceder, porque (creo) los cambios realizados a los contactos sólo funcionan una vez que se guarda. @CJK la nueva versión anterior funciona como está previsto, sin embargo.

Ahora, es tan fácil como ir bajando un montón de elementos duplicados a uno, como claramente es eliminar a todos ellos?

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X