That's weird. I'm trying to figure out why mine takes another pass after encountering end of string (even if I specify that the separator can be end-of-string). Meanwhile, I'll point out that your method finds only one field in '@' (instead of two empty ones — if there's no newline after the @).
Update: this seems to work:
my @pieces = /(?:^|\G@)((?:#.|[^@])*)/sg;
Still don't know why I couldn't get it to realize it had hit end of string. My guess is, if end-of-string is not required to match, it takes another shot to make sure nothing matches.
Caution: Contents may have been coded under pressure.